001/* 002 * Java Genetic Algorithm Library (jenetics-6.0.0). 003 * Copyright (c) 2007-2020 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.Clock; 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 6.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 Clock _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 Clock 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 Clock} the engine is using for measuring the execution 525 * time. 526 * 527 * @return the clock used for measuring the execution time 528 */ 529 public Clock 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 return builder(problem.fitness(), problem.codec()); 634 } 635 636 /** 637 * Create a new evolution {@code Engine.Builder} with the given fitness 638 * function and chromosome templates. 639 * 640 * @param ff the fitness function 641 * @param chromosome the first chromosome 642 * @param chromosomes the chromosome templates 643 * @param <G> the gene type 644 * @param <C> the fitness function result type 645 * @return a new engine builder 646 * @throws java.lang.NullPointerException if one of the arguments is 647 * {@code null}. 648 */ 649 @SafeVarargs 650 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 651 Builder<G, C> builder( 652 final Function<? super Genotype<G>, ? extends C> ff, 653 final Chromosome<G> chromosome, 654 final Chromosome<G>... chromosomes 655 ) { 656 return builder(ff, Genotype.of(chromosome, chromosomes)); 657 } 658 659 660 /* ************************************************************************* 661 * Engine builder 662 **************************************************************************/ 663 664 665 /** 666 * Builder class for building GA {@code Engine} instances. 667 * 668 * @see Engine 669 * 670 * @param <G> the gene type 671 * @param <C> the fitness function result type 672 * 673 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 674 * @since 3.0 675 * @version 6.0 676 */ 677 public static final class Builder< 678 G extends Gene<?, G>, 679 C extends Comparable<? super C> 680 > 681 implements Copyable<Builder<G, C>> 682 { 683 684 // No default values for this properties. 685 private final Evaluator<G, C> _evaluator; 686 private final Factory<Genotype<G>> _genotypeFactory; 687 private Constraint<G, C> _constraint; 688 private Optimize _optimize = Optimize.MAXIMUM; 689 690 // Evolution parameters. 691 private final EvolutionParams.Builder<G, C> _evolutionParams = 692 EvolutionParams.builder(); 693 694 695 // Engine execution environment. 696 private Executor _executor = commonPool(); 697 private Clock _clock = NanoClock.systemUTC(); 698 699 private EvolutionInterceptor<G, C> _interceptor = 700 EvolutionInterceptor.identity(); 701 702 /** 703 * Create a new evolution {@code Engine.Builder} with the given fitness 704 * evaluator and genotype factory. This is the most general way for 705 * creating an engine builder. 706 * 707 * @since 5.0 708 * 709 * @see Engine#builder(Function, Codec) 710 * @see Engine#builder(Function, Factory) 711 * @see Engine#builder(Problem) 712 * @see Engine#builder(Function, Chromosome, Chromosome[]) 713 * 714 * @param evaluator the fitness evaluator 715 * @param genotypeFactory the genotype factory 716 * @throws NullPointerException if one of the arguments is {@code null}. 717 */ 718 public Builder( 719 final Evaluator<G, C> evaluator, 720 final Factory<Genotype<G>> genotypeFactory 721 ) { 722 _genotypeFactory = requireNonNull(genotypeFactory); 723 _evaluator = requireNonNull(evaluator); 724 } 725 726 /** 727 * Applies the given {@code setup} recipe to {@code this} engine builder. 728 * 729 * @since 6.0 730 * 731 * @param setup the setup recipe applying to {@code this} builder 732 * @return {@code this} builder, for command chaining 733 * @throws NullPointerException if the {@code setup} is {@code null}. 734 */ 735 public Builder<G, C> setup(final Setup<G, C> setup) { 736 setup.apply(this); 737 return this; 738 } 739 740 /** 741 * Set the evolution parameters used by the engine. 742 * 743 * @since 5.2 744 * 745 * @param params the evolution parameter 746 * @return {@code this} builder, for command chaining 747 * @throws NullPointerException if the {@code params} is {@code null}. 748 */ 749 public Builder<G, C> evolutionParams(final EvolutionParams<G, C> params) { 750 _evolutionParams.evolutionParams(params); 751 return this; 752 } 753 754 /** 755 * The selector used for selecting the offspring population. <i>Default 756 * values is set to {@code TournamentSelector<>(3)}.</i> 757 * 758 * @param selector used for selecting the offspring population 759 * @return {@code this} builder, for command chaining 760 * @throws NullPointerException if one of the {@code selector} is 761 * {@code null}. 762 */ 763 public Builder<G, C> offspringSelector(final Selector<G, C> selector) { 764 _evolutionParams.offspringSelector(selector); 765 return this; 766 } 767 768 /** 769 * The selector used for selecting the survivors population. <i>Default 770 * values is set to {@code TournamentSelector<>(3)}.</i> 771 * 772 * @param selector used for selecting survivors population 773 * @return {@code this} builder, for command chaining 774 * @throws NullPointerException if one of the {@code selector} is 775 * {@code null}. 776 */ 777 public Builder<G, C> survivorsSelector(final Selector<G, C> selector) { 778 _evolutionParams.survivorsSelector(selector); 779 return this; 780 } 781 782 /** 783 * The selector used for selecting the survivors and offspring 784 * population. <i>Default values is set to 785 * {@code TournamentSelector<>(3)}.</i> 786 * 787 * @param selector used for selecting survivors and offspring population 788 * @return {@code this} builder, for command chaining 789 * @throws NullPointerException if one of the {@code selector} is 790 * {@code null}. 791 */ 792 public Builder<G, C> selector(final Selector<G, C> selector) { 793 _evolutionParams.selector(selector); 794 return this; 795 } 796 797 /** 798 * The alterers used for alter the offspring population. <i>Default 799 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by 800 * {@code new Mutator<>(0.15)}.</i> 801 * 802 * @param first the first alterer used for alter the offspring 803 * population 804 * @param rest the rest of the alterers used for alter the offspring 805 * population 806 * @return {@code this} builder, for command chaining 807 * @throws NullPointerException if one of the alterers is {@code null}. 808 */ 809 @SafeVarargs 810 public final Builder<G, C> alterers( 811 final Alterer<G, C> first, 812 final Alterer<G, C>... rest 813 ) { 814 _evolutionParams.alterers(first, rest); 815 return this; 816 } 817 818 /** 819 * The phenotype constraint is used for detecting invalid individuals 820 * and repairing them. 821 * 822 * <p><i>Default implementation uses {@code Phenotype::isValid} for 823 * validating the phenotype.</i></p> 824 * 825 * @since 5.0 826 * 827 * @param constraint phenotype constraint which can override the default 828 * implementation the {@link Phenotype#isValid()} method and repairs 829 * invalid phenotypes when needed. 830 * @return {@code this} builder, for command chaining 831 * @throws NullPointerException if one of the {@code constraint} is 832 * {@code null}. 833 */ 834 public Builder<G, C> constraint(final Constraint<G, C> constraint) { 835 _constraint = constraint; 836 return this; 837 } 838 839 /** 840 * The optimization strategy used by the engine. <i>Default values is 841 * set to {@code Optimize.MAXIMUM}.</i> 842 * 843 * @param optimize the optimization strategy used by the engine 844 * @return {@code this} builder, for command chaining 845 * @throws NullPointerException if one of the {@code optimize} is 846 * {@code null}. 847 */ 848 public Builder<G, C> optimize(final Optimize optimize) { 849 _optimize = requireNonNull(optimize); 850 return this; 851 } 852 853 /** 854 * Set to a fitness maximizing strategy. 855 * 856 * @since 3.4 857 * 858 * @return {@code this} builder, for command chaining 859 */ 860 public Builder<G, C> maximizing() { 861 return optimize(Optimize.MAXIMUM); 862 } 863 864 /** 865 * Set to a fitness minimizing strategy. 866 * 867 * @since 3.4 868 * 869 * @return {@code this} builder, for command chaining 870 */ 871 public Builder<G, C> minimizing() { 872 return optimize(Optimize.MINIMUM); 873 } 874 875 /** 876 * The offspring fraction. <i>Default values is set to {@code 0.6}.</i> 877 * This method call is equivalent to 878 * {@code survivorsFraction(1 - offspringFraction)} and will override 879 * any previously set survivors-fraction. 880 * 881 * @see #survivorsFraction(double) 882 * 883 * @param fraction the offspring fraction 884 * @return {@code this} builder, for command chaining 885 * @throws java.lang.IllegalArgumentException if the fraction is not 886 * within the range [0, 1]. 887 */ 888 public Builder<G, C> offspringFraction(final double fraction) { 889 _evolutionParams.offspringFraction(fraction); 890 return this; 891 } 892 893 /** 894 * The survivors fraction. <i>Default values is set to {@code 0.4}.</i> 895 * This method call is equivalent to 896 * {@code offspringFraction(1 - survivorsFraction)} and will override 897 * any previously set offspring-fraction. 898 * 899 * @since 3.8 900 * 901 * @see #offspringFraction(double) 902 * 903 * @param fraction the survivors fraction 904 * @return {@code this} builder, for command chaining 905 * @throws java.lang.IllegalArgumentException if the fraction is not 906 * within the range [0, 1]. 907 */ 908 public Builder<G, C> survivorsFraction(final double fraction) { 909 return offspringFraction(1 - fraction); 910 } 911 912 /** 913 * The number of offspring individuals. 914 * 915 * @since 3.8 916 * 917 * @param size the number of offspring individuals. 918 * @return {@code this} builder, for command chaining 919 * @throws java.lang.IllegalArgumentException if the size is not 920 * within the range [0, population-size]. 921 */ 922 public Builder<G, C> offspringSize(final int size) { 923 if (size < 0) { 924 throw new IllegalArgumentException(format( 925 "Offspring size must be greater or equal zero, but was %s.", 926 size 927 )); 928 } 929 930 return offspringFraction(size/(double)_evolutionParams.populationSize()); 931 } 932 933 /** 934 * The number of survivors. 935 * 936 * @since 3.8 937 * 938 * @param size the number of survivors. 939 * @return {@code this} builder, for command chaining 940 * @throws java.lang.IllegalArgumentException if the size is not 941 * within the range [0, population-size]. 942 */ 943 public Builder<G, C> survivorsSize(final int size) { 944 if (size < 0) { 945 throw new IllegalArgumentException(format( 946 "Survivors must be greater or equal zero, but was %s.", 947 size 948 )); 949 } 950 951 return survivorsFraction(size/(double)_evolutionParams.populationSize()); 952 } 953 954 /** 955 * The number of individuals which form the population. <i>Default 956 * values is set to {@code 50}.</i> 957 * 958 * @param size the number of individuals of a population 959 * @return {@code this} builder, for command chaining 960 * @throws java.lang.IllegalArgumentException if {@code size < 1} 961 */ 962 public Builder<G, C> populationSize(final int size) { 963 _evolutionParams.populationSize(size); 964 return this; 965 } 966 967 /** 968 * The maximal allowed age of a phenotype. <i>Default values is set to 969 * {@code 70}.</i> 970 * 971 * @param age the maximal phenotype age 972 * @return {@code this} builder, for command chaining 973 * @throws java.lang.IllegalArgumentException if {@code age < 1} 974 */ 975 public Builder<G, C> maximalPhenotypeAge(final long age) { 976 _evolutionParams.maximalPhenotypeAge(age); 977 return this; 978 } 979 980 /** 981 * The executor used by the engine. 982 * 983 * @param executor the executor used by the engine 984 * @return {@code this} builder, for command chaining 985 */ 986 public Builder<G, C> executor(final Executor executor) { 987 _executor = requireNonNull(executor); 988 return this; 989 } 990 991 /** 992 * The clock used for calculating the execution durations. 993 * 994 * @param clock the clock used for calculating the execution durations 995 * @return {@code this} builder, for command chaining 996 */ 997 public Builder<G, C> clock(final Clock clock) { 998 _clock = requireNonNull(clock); 999 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 1261