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