001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.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 * {@snippet lang="java":
055 * public class RealFunction {
056 *    // Definition of the fitness function.
057 *    private static Double eval(final Genotype<DoubleGene> gt) {
058 *        final double x = gt.gene().doubleValue();
059 *        return cos(0.5 + sin(x))*cos(x);
060 *    }
061 *
062 *    public static void main(String[] args) {
063 *        // Create/configuring the engine via its builder.
064 *        final Engine<DoubleGene, Double> engine = Engine
065 *            .builder(
066 *                RealFunction::eval,
067 *                DoubleChromosome.of(0.0, 2.0*PI))
068 *            .populationSize(500)
069 *            .optimize(Optimize.MINIMUM)
070 *            .alterers(
071 *                new Mutator<>(0.03),
072 *                new MeanAlterer<>(0.6))
073 *            .build();
074 *
075 *        // Execute the GA (engine).
076 *        final Phenotype<DoubleGene, Double> result = engine.stream()
077 *             // Truncate the evolution stream if no better individual could
078 *             // be found after 5 consecutive generations.
079 *            .limit(bySteadyFitness(5))
080 *             // Terminate the evolution after maximal 100 generations.
081 *            .limit(100)
082 *            .collect(toBestPhenotype());
083 *     }
084 * }
085 * }
086 *
087 * The architecture allows to decouple the configuration of the engine from the
088 * execution. The {@code Engine} is configured via the {@code Engine.Builder}
089 * class and can't be changed after creation. The actual <i>evolution</i> is
090 * performed by the {@link EvolutionStream}, which is created by the
091 * {@code Engine}.
092 *
093 * <H2>Concurrency</H2>
094 * By default, the engine uses the {@link ForkJoinPool#commonPool()} for
095 * executing the evolution steps and evaluating the fitness function concurrently.
096 * You can change the used execution services with the {@link Builder#executor(Executor)}
097 * method. If you want to use a different executor for evaluating the fitness
098 * functions, you have to set the {@link Builder#fitnessExecutor(BatchExecutor)}.
099 *
100 * {@snippet lang="java":
101 * final Engine<DoubleGene, Double> engine = Engine
102 *     .builder(null) // @replace substring='null' replacement="..."
103 *     // Using this execution service for parallelize the evolution steps.
104 *     .executor(Executors.newFixedThreadPool(5))
105 *     // Using one virtual thread for every fitness function evaluation.
106 *     .fitnessExecutor(BatchExecutor.ofVirtualThreads())
107 *     .build();
108 * }
109 *
110 * @implNote
111 *     This class is thread safe: The engine maintains no mutable state.
112 *     Therefore, it is safe to create multiple evolution streams with one
113 *     engine, which may be actually used in different threads.
114 *
115 * @see Engine.Builder
116 * @see EvolutionStart
117 * @see EvolutionResult
118 * @see EvolutionStream
119 * @see EvolutionStatistics
120 * @see Codec
121 * @see Constraint
122 *
123 * @param <G> the gene type
124 * @param <C> the fitness result type
125 *
126 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
127 * @since 3.0
128 * @version 7.0
129 */
130public final class Engine<
131        G extends Gene<?, G>,
132        C extends Comparable<? super C>
133>
134        implements
135                Evolution<G, C>,
136                EvolutionStreamable<G, C>,
137                Evaluator<G, C>
138{
139
140        // Problem definition.
141        private final Evaluator<G, C> _evaluator;
142        private final Factory<Genotype<G>> _genotypeFactory;
143        private final Constraint<G, C> _constraint;
144        private final Optimize _optimize;
145
146        // Evolution parameters.
147        private final EvolutionParams<G, C> _evolutionParams;
148
149        // Execution context for concurrent execution of evolving steps.
150        private final Executor _executor;
151        private final InstantSource _clock;
152        private final EvolutionInterceptor<G, C> _interceptor;
153
154
155        /**
156         * Create a new GA engine with the given parameters.
157         *
158         * @param evaluator the population fitness evaluator
159         * @param genotypeFactory the genotype factory this GA is working with.
160         * @param constraint phenotype constraint which can override the default
161         *        implementation the {@link Phenotype#isValid()} method and repairs
162         *        invalid phenotypes when needed.
163         * @param optimize the kind of optimization (minimize or maximize)
164         * @param evolutionParams the evolution parameters, which influences the
165         *        evolution process
166         * @param executor the executor used for executing the single evolved steps
167         * @param clock the clock used for calculating the timing results
168         * @param interceptor the evolution interceptor, which gives additional
169         *        possibilities to influence the actual evolution
170         * @throws NullPointerException if one of the arguments is {@code null}
171         * @throws IllegalArgumentException if the given integer values are smaller
172         *         than one.
173         */
174        Engine(
175                final Evaluator<G, C> evaluator,
176                final Factory<Genotype<G>> genotypeFactory,
177                final Constraint<G, C> constraint,
178                final Optimize optimize,
179                final EvolutionParams<G, C> evolutionParams,
180                final Executor executor,
181                final InstantSource clock,
182                final EvolutionInterceptor<G, C> interceptor
183        ) {
184                _evaluator = requireNonNull(evaluator);
185                _genotypeFactory = requireNonNull(genotypeFactory);
186                _constraint = requireNonNull(constraint);
187                _optimize = requireNonNull(optimize);
188                _evolutionParams = requireNonNull(evolutionParams);
189                _executor = requireNonNull(executor);
190                _clock = requireNonNull(clock);
191                _interceptor = requireNonNull(interceptor);
192        }
193
194        @Override
195        public EvolutionResult<G, C> evolve(final EvolutionStart<G, C> start) {
196                final EvolutionTiming timing = new EvolutionTiming(_clock);
197                timing.evolve.start();
198
199                final EvolutionStart<G, C> interceptedStart = _interceptor.before(start);
200
201                // Create initial population if `start` is empty.
202                final EvolutionStart<G, C> es = interceptedStart.population().isEmpty()
203                        ? evolutionStart(interceptedStart)
204                        : interceptedStart;
205
206                // Initial evaluation of the population.
207                final ISeq<Phenotype<G, C>> population = es.isDirty()
208                        ? timing.evaluation.timing(() -> eval(es.population()))
209                        : es.population();
210
211                // Select the offspring population.
212                final CompletableFuture<ISeq<Phenotype<G, C>>> offspring =
213                        supplyAsync(() ->
214                                timing.offspringSelection.timing(() ->
215                                        selectOffspring(population)
216                                ),
217                                _executor
218                        );
219
220                // Select the survivor population.
221                final CompletableFuture<ISeq<Phenotype<G, C>>> survivors =
222                        supplyAsync(() ->
223                                timing.survivorsSelection.timing(() ->
224                                        selectSurvivors(population)
225                                ),
226                                _executor
227                        );
228
229                // Altering the offspring population.
230                final CompletableFuture<AltererResult<G, C>> alteredOffspring =
231                        offspring.thenApplyAsync(off ->
232                                timing.offspringAlter.timing(() ->
233                                        _evolutionParams.alterer().alter(off, es.generation())
234                                ),
235                                _executor
236                        );
237
238                // Filter and replace invalid and old survivor individuals.
239                final CompletableFuture<FilterResult<G, C>> filteredSurvivors =
240                        survivors.thenApplyAsync(sur ->
241                                timing.survivorFilter.timing(() ->
242                                        filter(sur, es.generation())
243                                ),
244                                _executor
245                        );
246
247                // Filter and replace invalid and old offspring individuals.
248                final CompletableFuture<FilterResult<G, C>> filteredOffspring =
249                        alteredOffspring.thenApplyAsync(off ->
250                                timing.offspringFilter.timing(() ->
251                                        filter(off.population(), es.generation())
252                                ),
253                                _executor
254                        );
255
256                // Combining survivors and offspring to the new population.
257                final CompletableFuture<ISeq<Phenotype<G, C>>> nextPopulation =
258                        filteredSurvivors.thenCombineAsync(
259                                filteredOffspring,
260                                (s, o) -> ISeq.of(s.population().append(o.population())),
261                                _executor
262                        );
263
264                // Evaluate the fitness-function and wait for a result.
265                final ISeq<Phenotype<G, C>> pop = nextPopulation.join();
266                final ISeq<Phenotype<G, C>> result = timing.evaluation.timing(() ->
267                        eval(pop)
268                );
269
270                final int killCount =
271                        filteredOffspring.join().killCount() +
272                        filteredSurvivors.join().killCount();
273
274                final int invalidCount =
275                        filteredOffspring.join().invalidCount() +
276                        filteredSurvivors.join().invalidCount();
277
278                final int alterationCount = alteredOffspring.join().alterations();
279
280                EvolutionResult<G, C> er = EvolutionResult.of(
281                        _optimize,
282                        result,
283                        es.generation(),
284                        timing.toDurations(),
285                        killCount,
286                        invalidCount,
287                        alterationCount
288                );
289
290                final EvolutionResult<G, C> interceptedResult = _interceptor.after(er);
291                if (er != interceptedResult) {
292                        er = interceptedResult.withPopulation(
293                                timing.evaluation.timing(() ->
294                                        eval(interceptedResult.population())
295                        ));
296                }
297
298                timing.evolve.stop();
299
300                return er
301                        .withDurations(timing.toDurations())
302                        .clean();
303        }
304
305        // Selects the survivor population. A new population object is returned.
306        private ISeq<Phenotype<G, C>>
307        selectSurvivors(final ISeq<Phenotype<G, C>> population) {
308                return _evolutionParams.survivorsSize() > 0
309                        ? _evolutionParams.survivorsSelector()
310                                .select(population, _evolutionParams.survivorsSize(), _optimize)
311                        : ISeq.empty();
312        }
313
314        // Selects the offspring population. A new population object is returned.
315        private ISeq<Phenotype<G, C>>
316        selectOffspring(final ISeq<Phenotype<G, C>> population) {
317                return _evolutionParams.offspringSize() > 0
318                        ? _evolutionParams.offspringSelector()
319                                .select(population, _evolutionParams.offspringSize(), _optimize)
320                        : ISeq.empty();
321        }
322
323        // Filters out invalid and old individuals. Filtering is done in place.
324        private FilterResult<G, C> filter(
325                final Seq<Phenotype<G, C>> population,
326                final long generation
327        ) {
328                int killCount = 0;
329                int invalidCount = 0;
330
331                final MSeq<Phenotype<G, C>> pop = MSeq.of(population);
332                for (int i = 0, n = pop.size(); i < n; ++i) {
333                        final Phenotype<G, C> individual = pop.get(i);
334
335                        if (!_constraint.test(individual)) {
336                                pop.set(i, _constraint.repair(individual, generation));
337                                ++invalidCount;
338                        } else if (individual.age(generation) >
339                                                _evolutionParams.maximalPhenotypeAge())
340                        {
341                                pop.set(i, Phenotype.of(_genotypeFactory.newInstance(), generation));
342                                ++killCount;
343                        }
344                }
345
346                return new FilterResult<>(pop.toISeq(), killCount, invalidCount);
347        }
348
349
350        /* *************************************************************************
351         * Evaluation methods.
352         **************************************************************************/
353
354        /**
355         * Evaluates the fitness function of the given population with the configured
356         * {@link Evaluator} of this engine and returns a new population
357         * with its fitness value assigned.
358         *
359         * @since 5.0
360         *
361         * @see Evaluator
362         * @see Evaluator#eval(Seq)
363         *
364         * @param population the population to evaluate
365         * @return a new population with assigned fitness values
366         * @throws IllegalStateException if the configured fitness function doesn't
367         *         return a population with the same size as the input population.
368         *         This exception is also thrown if one of the populations
369         *         phenotype has no fitness value assigned.
370         */
371        @Override
372        public ISeq<Phenotype<G, C>> eval(final Seq<Phenotype<G, C>> population) {
373                final ISeq<Phenotype<G, C>> evaluated = _evaluator.eval(population);
374
375                if (population.size() != evaluated.size()) {
376                        throw new IllegalStateException(format(
377                                "Expected %d individuals, but got %d. " +
378                                        "Check your evaluator function.",
379                                population.size(), evaluated.size()
380                        ));
381                }
382                if (!evaluated.forAll(Phenotype::isEvaluated)) {
383                        throw new IllegalStateException(
384                                "Some phenotypes have no assigned fitness value. " +
385                                        "Check your evaluator function."
386                        );
387                }
388
389                return evaluated;
390        }
391
392
393        /* *************************************************************************
394         * Evolution Stream creation.
395         **************************************************************************/
396
397        @Override
398        public EvolutionStream<G, C>
399        stream(final Supplier<EvolutionStart<G, C>> start) {
400                return EvolutionStream.ofEvolution(
401                        () -> evolutionStart(start.get()),
402                        this
403                );
404        }
405
406        @Override
407        public EvolutionStream<G, C> stream(final EvolutionInit<G> init) {
408                return stream(evolutionStart(init));
409        }
410
411        private EvolutionStart<G, C>
412        evolutionStart(final EvolutionStart<G, C> start) {
413                final ISeq<Phenotype<G, C>> population = start.population();
414                final long gen = start.generation();
415
416                final Stream<Phenotype<G, C>> stream = Stream.concat(
417                        population.stream(),
418                        _genotypeFactory.instances()
419                                .map(gt -> Phenotype.of(gt, gen))
420                );
421
422                final ISeq<Phenotype<G, C>> pop = stream
423                        .limit(populationSize())
424                        .collect(ISeq.toISeq());
425
426                return EvolutionStart.of(pop, gen);
427        }
428
429        private EvolutionStart<G, C>
430        evolutionStart(final EvolutionInit<G> init) {
431                final ISeq<Genotype<G>> pop = init.population();
432                final long gen = init.generation();
433
434                return evolutionStart(
435                        EvolutionStart.of(
436                                pop.map(gt -> Phenotype.of(gt, gen)),
437                                gen
438                        )
439                );
440        }
441
442        /* *************************************************************************
443         * Property access methods.
444         **************************************************************************/
445
446        /**
447         * Return the used genotype {@link Factory} of the GA. The genotype factory
448         * is used for creating the initial population and new, random individuals
449         * when needed (as replacement for invalid and/or died genotypes).
450         *
451         * @return the used genotype {@link Factory} of the GA.
452         */
453        public Factory<Genotype<G>> genotypeFactory() {
454                return _genotypeFactory;
455        }
456
457        /**
458         * Return the constraint of the evolution problem.
459         *
460         * @since 5.0
461         *
462         * @return the constraint of the evolution problem
463         */
464        public Constraint<G, C> constraint() {
465                return _constraint;
466        }
467
468        /**
469         * Return the used survivor {@link Selector} of the GA.
470         *
471         * @return the used survivor {@link Selector} of the GA.
472         */
473        public Selector<G, C> survivorsSelector() {
474                return _evolutionParams.survivorsSelector();
475        }
476
477        /**
478         * Return the used offspring {@link Selector} of the GA.
479         *
480         * @return the used offspring {@link Selector} of the GA.
481         */
482        public Selector<G, C> offspringSelector() {
483                return _evolutionParams.offspringSelector();
484        }
485
486        /**
487         * Return the used {@link Alterer} of the GA.
488         *
489         * @return the used {@link Alterer} of the GA.
490         */
491        public Alterer<G, C> alterer() {
492                return _evolutionParams.alterer();
493        }
494
495        /**
496         * Return the number of selected offspring.
497         *
498         * @return the number of selected offspring
499         */
500        public int offspringSize() {
501                return _evolutionParams.offspringSize();
502        }
503
504        /**
505         * The number of selected survivors.
506         *
507         * @return the number of selected survivors
508         */
509        public int survivorsSize() {
510                return _evolutionParams.survivorsSize();
511        }
512
513        /**
514         * Return the number of individuals of a population.
515         *
516         * @return the number of individuals of a population
517         */
518        public int populationSize() {
519                return _evolutionParams.populationSize();
520        }
521
522        /**
523         * Return the maximal allowed phenotype age.
524         *
525         * @return the maximal allowed phenotype age
526         */
527        public long maximalPhenotypeAge() {
528                return _evolutionParams.maximalPhenotypeAge();
529        }
530
531        /**
532         * Return the optimization strategy.
533         *
534         * @return the optimization strategy
535         */
536        public Optimize optimize() {
537                return _optimize;
538        }
539
540        /**
541         * Return the {@link InstantSource} the engine is using for measuring the
542         * execution time.
543         *
544         * @return the clock used for measuring the execution time
545         */
546        public InstantSource clock() {
547                return _clock;
548        }
549
550        /**
551         * Return the {@link Executor} the engine is using for executing the
552         * evolution steps.
553         *
554         * @return the executor used for performing the evolution steps
555         */
556        public Executor executor() {
557                return _executor;
558        }
559
560        /**
561         * Return the evolution interceptor.
562         *
563         * @since 6.0
564         *
565         * @return the evolution result mapper
566         */
567        public EvolutionInterceptor<G, C> interceptor() {
568                return _interceptor;
569        }
570
571        /**
572         * Create a new evolution {@code Engine.Builder} initialized with the values
573         * of the current evolution {@code Engine}. With this method, the evolution
574         * engine can serve as a template for a new one.
575         *
576         * @return a new engine builder
577         */
578        public Builder<G, C> toBuilder() {
579                return new Builder<>(_evaluator, _genotypeFactory)
580                        .clock(_clock)
581                        .executor(_executor)
582                        .optimize(_optimize)
583                        .constraint(_constraint)
584                        .evolutionParams(_evolutionParams)
585                        .interceptor(_interceptor);
586        }
587
588
589        /* *************************************************************************
590         * Static Builder methods.
591         **************************************************************************/
592
593        /**
594         * Create a new evolution {@code Engine.Builder} with the given fitness
595         * function and genotype factory.
596         *
597         * @param ff the fitness function
598         * @param gtf the genotype factory
599         * @param <G> the gene type
600         * @param <C> the fitness function result type
601         * @return a new engine builder
602         * @throws java.lang.NullPointerException if one of the arguments is
603         *         {@code null}.
604         */
605        public static <G extends Gene<?, G>, C extends Comparable<? super C>>
606        Builder<G, C> builder(
607                final Function<? super Genotype<G>, ? extends C> ff,
608                final Factory<Genotype<G>> gtf
609        ) {
610                return new Builder<>(
611                        new FitnessEvaluator<>(ff, BatchExecutor.of(commonPool())),
612                        gtf
613                );
614        }
615
616        /**
617         * Create a new evolution {@code Engine.Builder} with the given fitness
618         * function and problem {@code codec}.
619         *
620         * @since 3.2
621         *
622         * @param ff the fitness evaluator
623         * @param codec the problem codec
624         * @param <T> the fitness function input type
625         * @param <C> the fitness function result type
626         * @param <G> the gene type
627         * @return a new engine builder
628         * @throws java.lang.NullPointerException if one of the arguments is
629         *         {@code null}.
630         */
631        public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
632        Builder<G, C> builder(
633                final Function<? super T, ? extends C> ff,
634                final Codec<T, G> codec
635        ) {
636                return builder(ff.compose(codec.decoder()), codec.encoding());
637        }
638
639        /**
640         * Create a new evolution {@code Engine.Builder} for the given
641         * {@link Problem}.
642         *
643         * @since 3.4
644         *
645         * @param problem the problem to be solved by the evolution {@code Engine}
646         * @param <T> the (<i>native</i>) argument type of the problem fitness function
647         * @param <G> the gene type the evolution engine is working with
648         * @param <C> the result type of the fitness function
649         * @return Create a new evolution {@code Engine.Builder}
650         */
651        public static <T, G extends Gene<?, G>, C extends Comparable<? super C>>
652        Builder<G, C> builder(final Problem<T, G, C> problem) {
653                final var builder = builder(problem.fitness(), problem.codec());
654                problem.constraint().ifPresent(builder::constraint);
655                return builder;
656        }
657
658        /**
659         * Create a new evolution {@code Engine.Builder} with the given fitness
660         * function and chromosome templates.
661         *
662         * @param ff the fitness function
663         * @param chromosome the first chromosome
664         * @param chromosomes the chromosome templates
665         * @param <G> the gene type
666         * @param <C> the fitness function result type
667         * @return a new engine builder
668         * @throws java.lang.NullPointerException if one of the arguments is
669         *         {@code null}.
670         */
671        @SafeVarargs
672        public static <G extends Gene<?, G>, C extends Comparable<? super C>>
673        Builder<G, C> builder(
674                final Function<? super Genotype<G>, ? extends C> ff,
675                final Chromosome<G> chromosome,
676                final Chromosome<G>... chromosomes
677        ) {
678                return builder(ff, Genotype.of(chromosome, chromosomes));
679        }
680
681
682        /* *************************************************************************
683         * Engine builder
684         **************************************************************************/
685
686
687        /**
688         * Builder class for building GA {@code Engine} instances.
689         *
690         * @see Engine
691         *
692         * @param <G> the gene type
693         * @param <C> the fitness function result type
694         *
695         * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
696         * @since 3.0
697         * @version 6.0
698         */
699        public static final class Builder<
700                G extends Gene<?, G>,
701                C extends Comparable<? super C>
702        >
703                implements Copyable<Builder<G, C>>
704        {
705
706                // No default values for this properties.
707                private final Evaluator<G, C> _evaluator;
708                private final Factory<Genotype<G>> _genotypeFactory;
709                private Constraint<G, C> _constraint;
710                private Optimize _optimize = Optimize.MAXIMUM;
711
712                // Evolution parameters.
713                private final EvolutionParams.Builder<G, C> _evolutionParams =
714                        EvolutionParams.builder();
715
716
717                // Engine execution environment.
718                private Executor _executor = commonPool();
719                private BatchExecutor _fitnessExecutor = null;
720                private InstantSource _clock = NanoClock.systemUTC();
721
722                private EvolutionInterceptor<G, C> _interceptor =
723                        EvolutionInterceptor.identity();
724
725                /**
726                 * Create a new evolution {@code Engine.Builder} with the given fitness
727                 * evaluator and genotype factory. This is the most general way of
728                 * creating an engine builder.
729                 *
730                 * @since 5.0
731                 *
732                 * @see Engine#builder(Function, Codec)
733                 * @see Engine#builder(Function, Factory)
734                 * @see Engine#builder(Problem)
735                 * @see Engine#builder(Function, Chromosome, Chromosome[])
736                 *
737                 * @param evaluator the fitness evaluator
738                 * @param gtf the genotype factory
739                 * @throws NullPointerException if one of the arguments is {@code null}.
740                 */
741                public Builder(
742                        final Evaluator<G, C> evaluator,
743                        final Factory<Genotype<G>> gtf
744                ) {
745                        _genotypeFactory = requireNonNull(gtf);
746                        _evaluator = requireNonNull(evaluator);
747                }
748
749                /**
750                 * Applies the given {@code setup} recipe to {@code this} engine builder.
751                 *
752                 * @since 6.0
753                 *
754                 * @param setup the setup recipe applying to {@code this} builder
755                 * @return {@code this} builder, for command chaining
756                 * @throws NullPointerException if the {@code setup} is {@code null}.
757                 */
758                public Builder<G, C> setup(final Setup<G, C> setup) {
759                        setup.apply(this);
760                        return this;
761                }
762
763                /**
764                 * Set the evolution parameters used by the engine.
765                 *
766                 * @since 5.2
767                 *
768                 * @param params the evolution parameter
769                 * @return {@code this} builder, for command chaining
770                 * @throws NullPointerException if the {@code params} is {@code null}.
771                 */
772                public Builder<G, C> evolutionParams(final EvolutionParams<G, C> params) {
773                        _evolutionParams.evolutionParams(params);
774                        return this;
775                }
776
777                /**
778                 * The selector used for selecting the offspring population. <i>Default
779                 * values is set to {@code TournamentSelector<>(3)}.</i>
780                 *
781                 * @param selector used for selecting the offspring population
782                 * @return {@code this} builder, for command chaining
783                 * @throws NullPointerException if one of the {@code selector} is
784                 *         {@code null}.
785                 */
786                public Builder<G, C> offspringSelector(final Selector<G, C> selector) {
787                        _evolutionParams.offspringSelector(selector);
788                        return this;
789                }
790
791                /**
792                 * The selector used for selecting the survivor population. <i>Default
793                 * values is set to {@code TournamentSelector<>(3)}.</i>
794                 *
795                 * @param selector used for selecting survivor population
796                 * @return {@code this} builder, for command chaining
797                 * @throws NullPointerException if one of the {@code selector} is
798                 *         {@code null}.
799                 */
800                public Builder<G, C> survivorsSelector(final Selector<G, C> selector) {
801                        _evolutionParams.survivorsSelector(selector);
802                        return this;
803                }
804
805                /**
806                 * The selector used for selecting the survivors and offspring
807                 * population. <i>Default values is set to
808                 * {@code TournamentSelector<>(3)}.</i>
809                 *
810                 * @param selector used for selecting survivors and offspring population
811                 * @return {@code this} builder, for command chaining
812                 * @throws NullPointerException if one of the {@code selector} is
813                 *         {@code null}.
814                 */
815                public Builder<G, C> selector(final Selector<G, C> selector) {
816                        _evolutionParams.selector(selector);
817                        return this;
818                }
819
820                /**
821                 * The alterers used for alter the offspring population. <i>Default
822                 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
823                 * {@code new Mutator<>(0.15)}.</i>
824                 *
825                 * @param first the first alterer used for alter the offspring
826                 *        population
827                 * @param rest the rest of the alterers used for alter the offspring
828                 *        population
829                 * @return {@code this} builder, for command chaining
830                 * @throws NullPointerException if one of the alterers is {@code null}.
831                 */
832                @SafeVarargs
833                public final Builder<G, C> alterers(
834                        final Alterer<G, C> first,
835                        final Alterer<G, C>... rest
836                ) {
837                        _evolutionParams.alterers(first, rest);
838                        return this;
839                }
840
841                /**
842                 * The phenotype constraint is used for detecting invalid individuals
843                 * and repairing them.
844                 *
845                 * <p><i>Default implementation uses {@code Phenotype::isValid} for
846                 * validating the phenotype.</i></p>
847                 *
848                 * @since 5.0
849                 *
850                 * @param constraint phenotype constraint which can override the default
851                 *        implementation the {@link Phenotype#isValid()} method and repairs
852                 *        invalid phenotypes when needed.
853                 * @return {@code this} builder, for command chaining
854                 * @throws NullPointerException if one of the {@code constraint} is
855                 *         {@code null}.
856                 */
857                public Builder<G, C> constraint(final Constraint<G, C> constraint) {
858                        _constraint = constraint;
859                        return this;
860                }
861
862                /**
863                 * The optimization strategy used by the engine. <i>Default values is
864                 * set to {@code Optimize.MAXIMUM}.</i>
865                 *
866                 * @param optimize the optimization strategy used by the engine
867                 * @return {@code this} builder, for command chaining
868                 * @throws NullPointerException if one of the {@code optimize} is
869                 *         {@code null}.
870                 */
871                public Builder<G, C> optimize(final Optimize optimize) {
872                        _optimize = requireNonNull(optimize);
873                        return this;
874                }
875
876                /**
877                 * Set to a fitness-maximizing strategy.
878                 *
879                 * @since 3.4
880                 *
881                 * @return {@code this} builder, for command chaining
882                 */
883                public Builder<G, C> maximizing() {
884                        return optimize(Optimize.MAXIMUM);
885                }
886
887                /**
888                 * Set to a fitness minimizing strategy.
889                 *
890                 * @since 3.4
891                 *
892                 * @return {@code this} builder, for command chaining
893                 */
894                public Builder<G, C> minimizing() {
895                        return optimize(Optimize.MINIMUM);
896                }
897
898                /**
899                 * The offspring fraction. <i>Default values is set to {@code 0.6}.</i>
900                 * This method call is equivalent to
901                 * {@code survivorsFraction(1 - offspringFraction)} and will override
902                 * any previously set survivors-fraction.
903                 *
904                 * @see #survivorsFraction(double)
905                 *
906                 * @param fraction the offspring fraction
907                 * @return {@code this} builder, for command chaining
908                 * @throws java.lang.IllegalArgumentException if the fraction is not
909                 *         within the range [0, 1].
910                 */
911                public Builder<G, C> offspringFraction(final double fraction) {
912                        _evolutionParams.offspringFraction(fraction);
913                        return this;
914                }
915
916                /**
917                 * The survivor fraction. <i>Default values is set to {@code 0.4}.</i>
918                 * This method call is equivalent to
919                 * {@code offspringFraction(1 - survivorsFraction)} and will override
920                 * any previously set offspring-fraction.
921                 *
922                 * @since 3.8
923                 *
924                 * @see #offspringFraction(double)
925                 *
926                 * @param fraction the survivor fraction
927                 * @return {@code this} builder, for command chaining
928                 * @throws java.lang.IllegalArgumentException if the fraction is not
929                 *         within the range [0, 1].
930                 */
931                public Builder<G, C> survivorsFraction(final double fraction) {
932                        return offspringFraction(1 - fraction);
933                }
934
935                /**
936                 * The number of offspring individuals.
937                 *
938                 * @since 3.8
939                 *
940                 * @param size the number of offspring individuals.
941                 * @return {@code this} builder, for command chaining
942                 * @throws java.lang.IllegalArgumentException if the size is not
943                 *         within the range [0, population-size].
944                 */
945                public Builder<G, C> offspringSize(final int size) {
946                        if (size < 0) {
947                                throw new IllegalArgumentException(format(
948                                        "Offspring size must be greater or equal zero, but was %s.",
949                                        size
950                                ));
951                        }
952
953                        return offspringFraction(size/(double)_evolutionParams.populationSize());
954                }
955
956                /**
957                 * The number of survivors.
958                 *
959                 * @since 3.8
960                 *
961                 * @param size the number of survivors.
962                 * @return {@code this} builder, for command chaining
963                 * @throws java.lang.IllegalArgumentException if the size is not
964                 *         within the range [0, population-size].
965                 */
966                public Builder<G, C> survivorsSize(final int size) {
967                        if (size < 0) {
968                                throw new IllegalArgumentException(format(
969                                        "Survivors must be greater or equal zero, but was %s.",
970                                        size
971                                ));
972                        }
973
974                        return survivorsFraction(size/(double)_evolutionParams.populationSize());
975                }
976
977                /**
978                 * The number of individuals which form the population. <i>Default
979                 * values is set to {@code 50}.</i>
980                 *
981                 * @param size the number of individuals of a population
982                 * @return {@code this} builder, for command chaining
983                 * @throws java.lang.IllegalArgumentException if {@code size < 1}
984                 */
985                public Builder<G, C> populationSize(final int size) {
986                        _evolutionParams.populationSize(size);
987                        return this;
988                }
989
990                /**
991                 * The maximal allowed age of a phenotype. <i>Default values is set to
992                 * {@code 70}.</i>
993                 *
994                 * @param age the maximal phenotype age
995                 * @return {@code this} builder, for command chaining
996                 * @throws java.lang.IllegalArgumentException if {@code age < 1}
997                 */
998                public Builder<G, C> maximalPhenotypeAge(final long age) {
999                        _evolutionParams.maximalPhenotypeAge(age);
1000                        return this;
1001                }
1002
1003                /**
1004                 * The executor used by the engine.
1005                 *
1006                 * @apiNote
1007                 * If no dedicated {@link Evaluator} is defined, this is also the
1008                 * executor, used for evaluating the fitness functions.
1009                 *
1010                 * @param executor the executor used by the engine
1011                 * @return {@code this} builder, for command chaining
1012                 */
1013                public Builder<G, C> executor(final Executor executor) {
1014                        _executor = requireNonNull(executor);
1015                        return this;
1016                }
1017
1018                /**
1019                 * This executor is used for evaluating the fitness functions.
1020                 *
1021                 * @apiNote
1022                 * If a dedicated {@link Evaluator} is defined, this executor is not
1023                 * used.
1024                 *
1025                 * @since 8.0
1026                 *
1027                 * @param executor the executor used for evaluating the fitness functions
1028                 * @return {@code this} builder, for command chaining
1029                 */
1030                public Builder<G, C> fitnessExecutor(final BatchExecutor executor) {
1031                        _fitnessExecutor = requireNonNull(executor);
1032                        return this;
1033                }
1034
1035                /**
1036                 * The clock used for calculating the execution durations.
1037                 *
1038                 * @param clock the clock used for calculating the execution durations
1039                 * @return {@code this} builder, for command chaining
1040                 */
1041                public Builder<G, C> clock(final InstantSource clock) {
1042                        _clock = requireNonNull(clock);
1043                        return this;
1044                }
1045
1046                /**
1047                 * The evolution interceptor, which allows changing the evolution start
1048                 * and result.
1049                 *
1050                 * @since 6.0
1051                 * @see EvolutionResult#toUniquePopulation()
1052                 *
1053                 * @param interceptor the evolution interceptor
1054                 * @return {@code this} builder, for command chaining
1055                 * @throws NullPointerException if the given {@code interceptor} is
1056                 *         {@code null}
1057                 */
1058                public Builder<G, C>
1059                interceptor(final EvolutionInterceptor<G, C> interceptor) {
1060                        _interceptor = requireNonNull(interceptor);
1061                        return this;
1062                }
1063
1064                /**
1065                 * Builds a new {@code Engine} instance from the set properties.
1066                 *
1067                 * @return a new {@code Engine} instance from the set properties
1068                 */
1069                public Engine<G, C> build() {
1070                        return new Engine<>(
1071                                __evaluator(),
1072                                _genotypeFactory,
1073                                __constraint(),
1074                                _optimize,
1075                                _evolutionParams.build(),
1076                                _executor,
1077                                _clock,
1078                                _interceptor
1079                        );
1080                }
1081
1082                private Evaluator<G, C> __evaluator() {
1083                        return _evaluator instanceof FitnessEvaluator<G, C> fe
1084                                ? new FitnessEvaluator<>(fe.function(), fitnessExecutor())
1085                                : _evaluator;
1086                }
1087
1088                private Constraint<G, C> __constraint() {
1089                        return _constraint == null
1090                                ? RetryConstraint.of(_genotypeFactory)
1091                                : _constraint;
1092                }
1093
1094                /* *********************************************************************
1095                 * Current properties
1096                 ***********************************************************************/
1097
1098                /**
1099                 * Return the used {@link Alterer} of the GA.
1100                 *
1101                 * @return the used {@link Alterer} of the GA.
1102                 */
1103                public Alterer<G, C> alterer() {
1104                        return _evolutionParams.alterer();
1105                }
1106
1107                /**
1108                 * Return the {@link InstantSource} the engine is using for measuring
1109                 * the execution time.
1110                 *
1111                 * @since 3.1
1112                 *
1113                 * @return the clock used for measuring the execution time
1114                 */
1115                public InstantSource clock() {
1116                        return _clock;
1117                }
1118
1119                /**
1120                 * Return the {@link Executor} the engine is using for executing the
1121                 * evolution steps.
1122                 *
1123                 * @since 3.1
1124                 *
1125                 * @return the executor used for performing the evolution steps
1126                 */
1127                public Executor executor() {
1128                        return _executor;
1129                }
1130
1131                /**
1132                 * Return the batch executor, used for evaluating the fitness functions.
1133                 *
1134                 * @since 8.0
1135                 *
1136                 * @return the batch executor, used for evaluating the fitness functions
1137                 */
1138                public BatchExecutor fitnessExecutor() {
1139                        return _fitnessExecutor != null
1140                                ? _fitnessExecutor
1141                                : BatchExecutor.of(executor());
1142                }
1143
1144                /**
1145                 * Return the used genotype {@link Factory} of the GA. The genotype factory
1146                 * is used for creating the initial population and new, random individuals
1147                 * when needed (as replacement for invalid and/or died genotypes).
1148                 *
1149                 * @since 3.1
1150                 *
1151                 * @return the used genotype {@link Factory} of the GA.
1152                 */
1153                public Factory<Genotype<G>> genotypeFactory() {
1154                        return _genotypeFactory;
1155                }
1156
1157                /**
1158                 * Return the constraint of the evolution problem.
1159                 *
1160                 * @since 5.0
1161                 *
1162                 * @return the constraint of the evolution problem
1163                 */
1164                public Constraint<G, C> constraint() {
1165                        return _constraint;
1166                }
1167
1168                /**
1169                 * Return the currently set evolution parameters.
1170                 *
1171                 * @since 5.2
1172                 *
1173                 * @return the currently set evolution parameters
1174                 */
1175                public EvolutionParams<G, C> evolutionParams() {
1176                        return _evolutionParams.build();
1177                }
1178
1179                /**
1180                 * Return the maximal allowed phenotype age.
1181                 *
1182                 * @since 3.1
1183                 *
1184                 * @return the maximal allowed phenotype age
1185                 */
1186                public long maximalPhenotypeAge() {
1187                        return _evolutionParams.maximalPhenotypeAge();
1188                }
1189
1190                /**
1191                 * Return the offspring fraction.
1192                 *
1193                 * @return the offspring fraction.
1194                 */
1195                public double offspringFraction() {
1196                        return _evolutionParams.offspringFraction();
1197                }
1198
1199                /**
1200                 * Return the used offspring {@link Selector} of the GA.
1201                 *
1202                 * @since 3.1
1203                 *
1204                 * @return the used offspring {@link Selector} of the GA.
1205                 */
1206                public Selector<G, C> offspringSelector() {
1207                        return _evolutionParams.offspringSelector();
1208                }
1209
1210                /**
1211                 * Return the used survivor {@link Selector} of the GA.
1212                 *
1213                 * @since 3.1
1214                 *
1215                 * @return the used survivor {@link Selector} of the GA.
1216                 */
1217                public Selector<G, C> survivorsSelector() {
1218                        return _evolutionParams.survivorsSelector();
1219                }
1220
1221                /**
1222                 * Return the optimization strategy.
1223                 *
1224                 * @since 3.1
1225                 *
1226                 * @return the optimization strategy
1227                 */
1228                public Optimize optimize() {
1229                        return _optimize;
1230                }
1231
1232                /**
1233                 * Return the number of individuals of a population.
1234                 *
1235                 * @since 3.1
1236                 *
1237                 * @return the number of individuals of a population
1238                 */
1239                public int populationSize() {
1240                        return _evolutionParams.populationSize();
1241                }
1242
1243                /**
1244                 * Return the evolution interceptor.
1245                 *
1246                 * @since 6.0
1247                 *
1248                 * @return the evolution interceptor
1249                 */
1250                public EvolutionInterceptor<G, C> interceptor() {
1251                        return _interceptor;
1252                }
1253
1254                /**
1255                 * Create a new builder, with the current configuration.
1256                 *
1257                 * @since 3.1
1258                 *
1259                 * @return a new builder, with the current configuration
1260                 */
1261                @Override
1262                public Builder<G, C> copy() {
1263                        return new Builder<>(_evaluator, _genotypeFactory)
1264                                .clock(_clock)
1265                                .executor(_executor)
1266                                .constraint(_constraint)
1267                                .optimize(_optimize)
1268                                .evolutionParams(_evolutionParams.build())
1269                                .interceptor(_interceptor);
1270                }
1271
1272        }
1273
1274
1275        /* *************************************************************************
1276         * Engine setup
1277         **************************************************************************/
1278
1279
1280        /**
1281         * This interface represents a recipe for configuring (setup) a given
1282         * {@link Builder}. It is mainly used for grouping mutually dependent
1283         * engine configurations. The following code snippet shows a possible usage
1284         * example.
1285         * {@snippet lang="java":
1286         * final Engine<CharacterGene, Integer> engine = Engine.builder(problem)
1287         *     .setup(new WeaselProgram<>())
1288         *     .build();
1289         * }
1290         *
1291         * @see Builder#setup(Setup)
1292         *
1293         * @param <G> the gene type
1294         * @param <C> the fitness result type
1295         *
1296         * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
1297         * @version 6.0
1298         * @since 6.0
1299         */
1300        @FunctionalInterface
1301        public interface Setup<
1302                G extends Gene<?, G>,
1303                C extends Comparable<? super C>
1304        > {
1305
1306                /**
1307                 * Applies {@code this} setup to the given engine {@code builder}.
1308                 *
1309                 * @param builder the engine builder to set up (configure)
1310                 */
1311                void apply(final Builder<G, C> builder);
1312
1313        }
1314}
1315
1316
1317