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