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