001/* 002 * Java Genetic Algorithm Library (jenetics-9.1.0). 003 * Copyright (c) 2007-2026 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.util.Objects.requireNonNull; 023import static java.util.stream.Collectors.toMap; 024import static io.jenetics.engine.EvolutionInterceptor.ofAfter; 025import static io.jenetics.internal.util.SerialIO.readInt; 026import static io.jenetics.internal.util.SerialIO.readLong; 027import static io.jenetics.internal.util.SerialIO.writeInt; 028import static io.jenetics.internal.util.SerialIO.writeLong; 029 030import java.io.IOException; 031import java.io.InvalidObjectException; 032import java.io.ObjectInput; 033import java.io.ObjectInputStream; 034import java.io.ObjectOutput; 035import java.io.Serial; 036import java.io.Serializable; 037import java.util.Map; 038import java.util.Objects; 039import java.util.function.Function; 040import java.util.stream.Collector; 041import java.util.stream.Stream; 042 043import io.jenetics.Gene; 044import io.jenetics.Genotype; 045import io.jenetics.Optimize; 046import io.jenetics.Phenotype; 047import io.jenetics.internal.util.Lazy; 048import io.jenetics.stat.MinMax; 049import io.jenetics.util.Factory; 050import io.jenetics.util.ISeq; 051import io.jenetics.util.Seq; 052 053/** 054 * Represents a state of the GA after an evolution step. It also represents the 055 * final state of an evolution process and can be created with an appropriate 056 * collector: 057 * {@snippet lang="java": 058 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = null; // @replace substring='null' replacement="..." 059 * final EvolutionResult<EnumGene<Point>, Double> result = Engine.builder(tsm) 060 * .optimize(Optimize.MINIMUM) 061 * .build() 062 * .stream() 063 * .limit(100) 064 * .collect(EvolutionResult.toBestEvolutionResult()); 065 * } 066 * 067 * @implSpec 068 * This class implements the {@link Comparable} interface, which compares two 069 * {@link EvolutionResult} objects according its <em>optimal</em> fitness value. 070 * This means that the better evolution result is always <em>greater</em>, no 071 * matter if the fitness function is minimized or maximized. 072 * {@snippet lang="java": 073 * final EvolutionResult<DoubleGene, Double> result1 = null; // @replace substring='null' replacement="..." 074 * final EvolutionResult<DoubleGene, Double> result2 = null; // @replace substring='null' replacement="..." 075 * 076 * if (result1.compareTo(result2) > 0) { 077 * // Holds for maximizing evolution results. 078 * assert result1.bestFitness() > result2.bestFitness(); 079 * 080 * // Holds for minimizing evolution results. 081 * assert result1.bestFitness() < result2.bestFitness(); 082 * } 083 * } 084 * 085 * @see EvolutionStart 086 * @see Engine 087 * 088 * @param <G> the gene type 089 * @param <C> the fitness type 090 * 091 * @implNote 092 * This class is immutable and thread-safe. 093 * 094 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 095 * @since 3.0 096 * @version 6.0 097 */ 098public final class EvolutionResult< 099 G extends Gene<?, G>, 100 C extends Comparable<? super C> 101> 102 implements Comparable<EvolutionResult<G, C>>, Serializable 103{ 104 @Serial 105 private static final long serialVersionUID = 2L; 106 107 private final Optimize _optimize; 108 private final ISeq<Phenotype<G, C>> _population; 109 private final long _generation; 110 private final long _totalGenerations; 111 112 private final EvolutionDurations _durations; 113 private final int _killCount; 114 private final int _invalidCount; 115 private final int _alterCount; 116 117 private final boolean _dirty; 118 119 private final Lazy<Phenotype<G, C>> _best; 120 private final Lazy<Phenotype<G, C>> _worst; 121 122 private EvolutionResult( 123 final Optimize optimize, 124 final ISeq<Phenotype<G, C>> population, 125 final long generation, 126 final long totalGenerations, 127 final EvolutionDurations durations, 128 final int killCount, 129 final int invalidCount, 130 final int alterCount, 131 final boolean dirty 132 ) { 133 _optimize = requireNonNull(optimize); 134 _population = requireNonNull(population); 135 _generation = generation; 136 _totalGenerations = totalGenerations; 137 _durations = requireNonNull(durations); 138 _killCount = killCount; 139 _invalidCount = invalidCount; 140 _alterCount = alterCount; 141 _dirty = dirty; 142 143 _best = Lazy.of(() -> _population.stream() 144 .max(_optimize.ascending()) 145 .orElse(null) 146 ); 147 148 _worst = Lazy.of(() -> _population.stream() 149 .min(_optimize.ascending()) 150 .orElse(null) 151 ); 152 } 153 154 /** 155 * Return the optimization strategy used. 156 * 157 * @return the optimization strategy used 158 */ 159 public Optimize optimize() { 160 return _optimize; 161 } 162 163 /** 164 * Return the population after the evolution step. 165 * 166 * @return the population after the evolution step 167 */ 168 public ISeq<Phenotype<G, C>> population() { 169 return _population; 170 } 171 172 /** 173 * Return the current list of genotypes of this evolution result. 174 * 175 * @since 5.2 176 * 177 * @return the list of genotypes of this evolution result. 178 */ 179 public ISeq<Genotype<G>> genotypes() { 180 return _population.map(Phenotype::genotype); 181 } 182 183 /** 184 * The current generation. 185 * 186 * @return the current generation 187 */ 188 public long generation() { 189 return _generation; 190 } 191 192 /** 193 * Return the generation count evaluated so far. 194 * 195 * @return the total number of generations evaluated so far 196 */ 197 public long totalGenerations() { 198 return _totalGenerations; 199 } 200 201 /** 202 * Return the timing (meta) information of the evolution step. 203 * 204 * @return the timing (meta) information of the evolution step 205 */ 206 public EvolutionDurations durations() { 207 return _durations; 208 } 209 210 /** 211 * Return the number of killed individuals. 212 * 213 * @return the number of killed individuals 214 */ 215 public int killCount() { 216 return _killCount; 217 } 218 219 /** 220 * Return the number of invalid individuals. 221 * 222 * @return the number of invalid individuals 223 */ 224 public int invalidCount() { 225 return _invalidCount; 226 } 227 228 /** 229 * The number of altered individuals. 230 * 231 * @return the number of altered individuals 232 */ 233 public int alterCount() { 234 return _alterCount; 235 } 236 237 /** 238 * Return the best {@code Phenotype} of the result population. 239 * 240 * @return the best {@code Phenotype} of the result population 241 */ 242 public Phenotype<G, C> bestPhenotype() { 243 return _best.get(); 244 } 245 246 /** 247 * Return the worst {@code Phenotype} of the result population. 248 * 249 * @return the worst {@code Phenotype} of the result population 250 */ 251 public Phenotype<G, C> worstPhenotype() { 252 return _worst.get(); 253 } 254 255 /** 256 * Return the best population fitness. 257 * 258 * @return The best population fitness. 259 */ 260 public C bestFitness() { 261 return _best.get() != null 262 ? _best.get().fitness() 263 : null; 264 } 265 266 /** 267 * Return the worst population fitness. 268 * 269 * @return The worst population fitness. 270 */ 271 public C worstFitness() { 272 return _worst.get() != null ? _worst.get().fitness() : null; 273 } 274 275 /** 276 * Return the next evolution start object with the current population and 277 * the incremented generation. 278 * 279 * @since 4.1 280 * 281 * @return the next evolution start object 282 */ 283 public EvolutionStart<G, C> next() { 284 return new EvolutionStart<>(_population, _totalGenerations + 1, _dirty); 285 } 286 287 /** 288 * Return the current evolution result object as an {@code EvolutionStart} 289 * object with the current population and current total generation. 290 * 291 * @since 4.1 292 * 293 * @return the current result as evolution start 294 */ 295 public EvolutionStart<G, C> toEvolutionStart() { 296 return new EvolutionStart<>(_population, _totalGenerations, _dirty); 297 } 298 299 /** 300 * Compare {@code this} evolution result with another one, according the 301 * population's best individual. 302 * 303 * @param other the other evolution result to compare 304 * @return a negative integer, zero, or a positive integer as this result 305 * is less than, equal to, or greater than the specified result. 306 */ 307 @Override 308 public int compareTo(final EvolutionResult<G, C> other) { 309 return _optimize.compare(_best.get(), other._best.get()); 310 } 311 312 private EvolutionResult<G, C> withTotalGenerations(final long total) { 313 return EvolutionResult.of( 314 _optimize, 315 _population, 316 _generation, 317 total, 318 _durations, 319 _killCount, 320 _invalidCount, 321 _alterCount 322 ); 323 } 324 325 EvolutionResult<G, C> withPopulation(final ISeq<Phenotype<G, C>> population) { 326 return EvolutionResult.of( 327 optimize(), 328 population, 329 generation(), 330 totalGenerations(), 331 durations(), 332 killCount(), 333 invalidCount(), 334 alterCount() 335 ); 336 } 337 338 EvolutionResult<G, C> withDurations(final EvolutionDurations durations) { 339 return EvolutionResult.of( 340 optimize(), 341 population(), 342 generation(), 343 totalGenerations(), 344 durations, 345 killCount(), 346 invalidCount(), 347 alterCount() 348 ); 349 } 350 351 EvolutionResult<G, C> clean() { 352 return new EvolutionResult<>( 353 optimize(), 354 population(), 355 generation(), 356 totalGenerations(), 357 durations(), 358 killCount(), 359 invalidCount(), 360 alterCount(), 361 false 362 ); 363 } 364 365 @Override 366 public int hashCode() { 367 return Objects.hash( 368 _optimize, 369 _population, 370 _generation, 371 _totalGenerations, 372 _durations, 373 _killCount, 374 _invalidCount, 375 _alterCount 376 ); 377 } 378 379 @Override 380 public boolean equals(final Object obj) { 381 return obj instanceof EvolutionResult<?, ?> other && 382 Objects.equals(_optimize, other._optimize) && 383 Objects.equals(_population, other._population) && 384 Objects.equals(_generation, other._generation) && 385 Objects.equals(_totalGenerations, other._totalGenerations) && 386 Objects.equals(_durations, other._durations) && 387 Objects.equals(_killCount, other._killCount) && 388 Objects.equals(_invalidCount, other._invalidCount) && 389 Objects.equals(_alterCount, other._alterCount); 390 } 391 392 393 /* ************************************************************************* 394 * Some static collector/factory methods. 395 * ************************************************************************/ 396 397 398 /** 399 * Return a collector which collects the best result of an evolution stream. 400 * {@snippet lang="java": 401 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = null; // @replace substring='null' replacement="..." 402 * final EvolutionResult<EnumGene<Point>, Double> result = Engine.builder(tsm) 403 * .optimize(Optimize.MINIMUM).build() 404 * .stream() 405 * .limit(100) 406 * .collect(EvolutionResult.toBestEvolutionResult()); 407 * } 408 * 409 * If the collected {@link EvolutionStream} is empty, the collector returns 410 * <b>{@code null}</b>. 411 * 412 * @param <G> the gene type 413 * @param <C> the fitness type 414 * @return a collector which collects the best result of an evolution stream 415 */ 416 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 417 Collector<EvolutionResult<G, C>, ?, EvolutionResult<G, C>> 418 toBestEvolutionResult() { 419 return Collector.of( 420 MinMax::of, 421 MinMax::accept, 422 MinMax::combine, 423 (MinMax<EvolutionResult<G, C>> mm) -> mm.max() != null 424 ? mm.max().withTotalGenerations(mm.count()) 425 : null 426 ); 427 } 428 429 /** 430 * Return a collector which collects the best phenotype of an evolution 431 * stream. 432 * {@snippet lang="java": 433 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = null; // @replace substring='null' replacement="..." 434 * final Phenotype<EnumGene<Point>, Double> result = Engine.builder(tsm) 435 * .optimize(Optimize.MINIMUM).build() 436 * .stream() 437 * .limit(100) 438 * .collect(EvolutionResult.toBestPhenotype()); 439 * } 440 * 441 * If the collected {@link EvolutionStream} is empty, the collector returns 442 * <b>{@code null}</b>. 443 * 444 * @param <G> the gene type 445 * @param <C> the fitness type 446 * @return a collector which collects the best phenotype of an evolution 447 * stream 448 */ 449 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 450 Collector<EvolutionResult<G, C>, ?, Phenotype<G, C>> 451 toBestPhenotype() { 452 return Collector.of( 453 MinMax::of, 454 MinMax::accept, 455 MinMax::combine, 456 (MinMax<EvolutionResult<G, C>> mm) -> mm.max() != null 457 ? mm.max().bestPhenotype() 458 : null 459 ); 460 } 461 462 /** 463 * Return a collector which collects the best genotype of an evolution 464 * stream. 465 * {@snippet lang="java": 466 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = null; // @replace substring='null' replacement="..." 467 * final Genotype<EnumGene<Point>> result = Engine.builder(tsm) 468 * .optimize(Optimize.MINIMUM).build() 469 * .stream() 470 * .limit(100) 471 * .collect(EvolutionResult.toBestGenotype()); 472 * } 473 * 474 * If the collected {@link EvolutionStream} is empty, the collector returns 475 * <b>{@code null}</b>. 476 * 477 * @param <G> the gene type 478 * @param <C> the fitness type 479 * @return a collector which collects the best genotype of an evolution 480 * stream 481 */ 482 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 483 Collector<EvolutionResult<G, C>, ?, Genotype<G>> 484 toBestGenotype() { 485 return Collector.of( 486 MinMax::of, 487 MinMax::accept, 488 MinMax::combine, 489 (MinMax<EvolutionResult<G, C>> mm) -> mm.max() != null 490 ? mm.max().bestPhenotype() != null 491 ? mm.max().bestPhenotype().genotype() 492 : null 493 : null 494 ); 495 } 496 497 /** 498 * Return a collector which collects the best <em>result</em> (in the native 499 * problem space). 500 * {@snippet lang="java": 501 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = null; // @replace substring='null' replacement="..." 502 * final ISeq<Point> route = Engine.builder(tsm) 503 * .optimize(Optimize.MINIMUM).build() 504 * .stream() 505 * .limit(100) 506 * .collect(EvolutionResult.toBestResult(tsm.codec().decoder())); 507 * } 508 * 509 * If the collected {@link EvolutionStream} is empty, the collector returns 510 * <b>{@code null}</b>. 511 * 512 * @since 3.6 513 * 514 * @param decoder the decoder which converts the {@code Genotype} into the 515 * result of the problem space. 516 * @param <T> the <em>native</em> problem result type 517 * @param <G> the gene type 518 * @param <C> the fitness result type 519 * @return a collector which collects the best result of an evolution stream 520 * @throws NullPointerException if the given {@code decoder} is {@code null} 521 */ 522 public static <G extends Gene<?, G>, C extends Comparable<? super C>, T> 523 Collector<EvolutionResult<G, C>, ?, T> 524 toBestResult(final Function<Genotype<G>, T> decoder) { 525 requireNonNull(decoder); 526 527 return Collector.of( 528 MinMax::of, 529 MinMax::accept, 530 MinMax::combine, 531 (MinMax<EvolutionResult<G, C>> mm) -> mm.max() != null 532 ? mm.max().bestPhenotype() != null 533 ? decoder.apply(mm.max().bestPhenotype().genotype()) 534 : null 535 : null 536 ); 537 } 538 539 /** 540 * Return a collector which collects the best <em>result</em> (in the native 541 * problem space). 542 * {@snippet lang="java": 543 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = null; // @replace substring='null' replacement="..." 544 * final ISeq<Point> route = Engine.builder(tsm) 545 * .optimize(Optimize.MINIMUM).build() 546 * .stream() 547 * .limit(100) 548 * .collect(EvolutionResult.toBestResult(tsm.codec())); 549 * } 550 * 551 * If the collected {@link EvolutionStream} is empty, the collector returns 552 * <b>{@code null}</b>. 553 * 554 * @since 3.6 555 * 556 * @param codec the problem decoder 557 * @param <T> the <em>native</em> problem result type 558 * @param <G> the gene type 559 * @param <C> the fitness result type 560 * @return a collector which collects the best result of an evolution stream 561 * @throws NullPointerException if the given {@code codec} is {@code null} 562 */ 563 public static <G extends Gene<?, G>, C extends Comparable<? super C>, T> 564 Collector<EvolutionResult<G, C>, ?, T> 565 toBestResult(final Codec<T, G> codec) { 566 return toBestResult(codec.decoder()); 567 } 568 569 /** 570 * Return a mapping function, which removes duplicate individuals from the 571 * population and replaces it with newly created one by the given genotype 572 * {@code factory}. 573 * {@snippet lang="java": 574 * final Problem<Double, DoubleGene, Integer> problem = null; // @replace substring='null' replacement="..." 575 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem) 576 * .interceptor(toUniquePopulation(problem.codec().encoding(), 100)) 577 * .build(); 578 * final Genotype<DoubleGene> best = engine.stream() 579 * .limit(100) 580 * .collect(EvolutionResult.toBestGenotype()); 581 * } 582 * 583 * @since 6.0 584 * @see Engine.Builder#interceptor(EvolutionInterceptor) 585 * 586 * @param factory the genotype factory which creates new individuals 587 * @param maxRetries the maximal number of genotype creations tries 588 * @param <G> the gene type 589 * @param <C> the fitness function result type 590 * @return a mapping function, which removes duplicate individuals from the 591 * population 592 * @throws NullPointerException if the given genotype {@code factory} is 593 * {@code null} 594 */ 595 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 596 EvolutionInterceptor<G, C> 597 toUniquePopulation(final Factory<Genotype<G>> factory, final int maxRetries) { 598 requireNonNull(factory); 599 return ofAfter(result -> uniquePopulation(factory, maxRetries, result)); 600 } 601 602 private static <G extends Gene<?, G>, C extends Comparable<? super C>> 603 EvolutionResult<G, C> uniquePopulation( 604 final Factory<Genotype<G>> factory, 605 final int maxRetries, 606 final EvolutionResult<G, C> result 607 ) { 608 final Seq<Phenotype<G, C>> population = result.population(); 609 final Map<Genotype<G>, Phenotype<G, C>> elements = 610 population.stream() 611 .collect(toMap( 612 Phenotype::genotype, 613 Function.identity(), 614 (a, _) -> a)); 615 616 EvolutionResult<G, C> uniques = result; 617 if (elements.size() < population.size()) { 618 int retries = 0; 619 while (elements.size() < population.size() && retries < maxRetries) { 620 final Genotype<G> gt = factory.newInstance(); 621 final Phenotype<G, C> pt = elements 622 .put(gt, Phenotype.of(gt, result.generation())); 623 if (pt != null) { 624 ++retries; 625 } 626 } 627 uniques = result.withPopulation( 628 Stream.concat(elements.values().stream(), population.stream()) 629 .limit(population.size()) 630 .collect(ISeq.toISeq()) 631 ); 632 } 633 634 return uniques; 635 } 636 637 638 /* ************************************************************************* 639 * Some collector and mapping functions. 640 * ************************************************************************/ 641 642 643 /** 644 * Return a mapping function, which removes duplicate individuals from the 645 * population and replaces it with newly created one by the given genotype 646 * {@code factory}. 647 * {@snippet lang="java": 648 * final Problem<Double, DoubleGene, Integer> problem = null; // @replace substring='null' replacement="..." 649 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem) 650 * .interceptor(toUniquePopulation(problem.codec().encoding())) 651 * .build(); 652 * final Genotype<DoubleGene> best = engine.stream() 653 * .limit(100) 654 * .collect(EvolutionResult.toBestGenotype()); 655 * } 656 * 657 * @since 6.0 658 * @see Engine.Builder#interceptor(EvolutionInterceptor) 659 * 660 * @param factory the genotype factory which creates new individuals 661 * @param <G> the gene type 662 * @param <C> the fitness function result type 663 * @return a mapping function, which removes duplicate individuals from the 664 * population 665 * @throws NullPointerException if the given genotype {@code factory} is 666 * {@code null} 667 */ 668 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 669 EvolutionInterceptor<G, C> 670 toUniquePopulation(final Factory<Genotype<G>> factory) { 671 return toUniquePopulation(factory, 100); 672 } 673 674 /** 675 * Return a mapping function, which removes duplicate individuals from the 676 * population and replaces it with newly created one by the existing 677 * genotype factory. 678 * {@snippet lang="java": 679 * final Problem<Double, DoubleGene, Integer> problem = null; // @replace substring='null' replacement="..." 680 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem) 681 * .interceptor(toUniquePopulation(10)) 682 * .build(); 683 * final Genotype<DoubleGene> best = engine.stream() 684 * .limit(100) 685 * .collect(EvolutionResult.toBestGenotype(5)); 686 * } 687 * 688 * @since 6.0 689 * @see Engine.Builder#interceptor(EvolutionInterceptor) 690 * 691 * @param maxRetries the maximal number of genotype creations tries 692 * @param <G> the gene type 693 * @param <C> the fitness function result type 694 * @return a mapping function, which removes duplicate individuals from the 695 * population 696 * @throws NullPointerException if the given genotype {@code factory} is 697 * {@code null} 698 */ 699 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 700 EvolutionInterceptor<G, C> toUniquePopulation(final int maxRetries) { 701 return ofAfter(result -> uniquePopulation( 702 result.population().get(0).genotype(), 703 maxRetries, 704 result 705 )); 706 } 707 708 /** 709 * Return a mapping function, which removes duplicate individuals from the 710 * population and replaces it with newly created one by the existing 711 * genotype factory. 712 * {@snippet lang="java": 713 * final Problem<Double, DoubleGene, Integer> problem = null; // @replace substring='null' replacement="..." 714 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem) 715 * .interceptor(EvolutionResult.toUniquePopulation()) 716 * .build(); 717 * final Genotype<DoubleGene> best = engine.stream() 718 * .limit(100) 719 * .collect(EvolutionResult.toBestGenotype()); 720 * } 721 * 722 * @since 6.0 723 * @see Engine.Builder#interceptor(EvolutionInterceptor) 724 * 725 * @param <G> the gene type 726 * @param <C> the fitness function result type 727 * @return a mapping function, which removes duplicate individuals from the 728 * population 729 * @throws NullPointerException if the given genotype {@code factory} is 730 * {@code null} 731 */ 732 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 733 EvolutionInterceptor<G, C> toUniquePopulation() { 734 return ofAfter(result -> uniquePopulation( 735 result.population().get(0).genotype(), 736 100, 737 result 738 )); 739 } 740 741 /** 742 * Return a new {@code EvolutionResult} object with the given values. 743 * 744 * @param optimize the optimization strategy used 745 * @param population the population after the evolution step 746 * @param generation the current generation 747 * @param totalGenerations the overall number of generations 748 * @param durations the timing (meta) information 749 * @param killCount the number of individuals which has been killed 750 * @param invalidCount the number of individuals which has been removed as 751 * invalid 752 * @param alterCount the number of individuals which has been altered 753 * @param <G> the gene type 754 * @param <C> the fitness type 755 * @return an new evolution result object 756 * @throws java.lang.NullPointerException if one of the parameters is 757 * {@code null} 758 */ 759 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 760 EvolutionResult<G, C> of( 761 final Optimize optimize, 762 final ISeq<Phenotype<G, C>> population, 763 final long generation, 764 final long totalGenerations, 765 final EvolutionDurations durations, 766 final int killCount, 767 final int invalidCount, 768 final int alterCount 769 ) { 770 return new EvolutionResult<>( 771 optimize, 772 population, 773 generation, 774 totalGenerations, 775 durations, 776 killCount, 777 invalidCount, 778 alterCount, 779 true 780 ); 781 } 782 783 /** 784 * Return a new {@code EvolutionResult} object with the given values. 785 * 786 * @param optimize the optimization strategy used 787 * @param population the population after the evolution step 788 * @param generation the current generation 789 * @param durations the timing (meta) information 790 * @param killCount the number of individuals which has been killed 791 * @param invalidCount the number of individuals which has been removed as 792 * invalid 793 * @param alterCount the number of individuals which has been altered 794 * @param <G> the gene type 795 * @param <C> the fitness type 796 * @return an new evolution result object 797 * @throws java.lang.NullPointerException if one of the parameters is 798 * {@code null} 799 */ 800 public static <G extends Gene<?, G>, C extends Comparable<? super C>> 801 EvolutionResult<G, C> of( 802 final Optimize optimize, 803 final ISeq<Phenotype<G, C>> population, 804 final long generation, 805 final EvolutionDurations durations, 806 final int killCount, 807 final int invalidCount, 808 final int alterCount 809 ) { 810 return new EvolutionResult<>( 811 optimize, 812 population, 813 generation, 814 generation, 815 durations, 816 killCount, 817 invalidCount, 818 alterCount, 819 true 820 ); 821 } 822 823 824 /* ************************************************************************* 825 * Java object serialization 826 * ************************************************************************/ 827 828 @Serial 829 private Object writeReplace() { 830 return new SerialProxy(SerialProxy.EVOLUTION_RESULT, this); 831 } 832 833 @Serial 834 private void readObject(final ObjectInputStream stream) 835 throws InvalidObjectException 836 { 837 throw new InvalidObjectException("Serialization proxy required."); 838 } 839 840 void write(final ObjectOutput out) throws IOException { 841 out.writeObject(_optimize); 842 out.writeObject(_population); 843 writeLong(_generation, out); 844 writeLong(_totalGenerations, out); 845 out.writeObject(_durations); 846 writeInt(_killCount, out); 847 writeInt(_invalidCount, out); 848 writeInt(_alterCount, out); 849 } 850 851 @SuppressWarnings({"unchecked", "rawtypes"}) 852 static Object read(final ObjectInput in) 853 throws IOException, ClassNotFoundException 854 { 855 return new EvolutionResult<>( 856 (Optimize)in.readObject(), 857 (ISeq)in.readObject(), 858 readLong(in), 859 readLong(in), 860 (EvolutionDurations)in.readObject(), 861 readInt(in), 862 readInt(in), 863 readInt(in), 864 true 865 ); 866 } 867 868}