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