001 /*
002 * Java Genetic Algorithm Library (jenetics-7.0.0).
003 * Copyright (c) 2007-2022 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020 package io.jenetics.engine;
021
022 import static java.util.Objects.requireNonNull;
023 import static java.util.stream.Collectors.toMap;
024 import static io.jenetics.engine.EvolutionInterceptor.ofAfter;
025 import static io.jenetics.internal.util.Hashes.hash;
026 import static io.jenetics.internal.util.SerialIO.readInt;
027 import static io.jenetics.internal.util.SerialIO.readLong;
028 import static io.jenetics.internal.util.SerialIO.writeInt;
029 import static io.jenetics.internal.util.SerialIO.writeLong;
030
031 import java.io.IOException;
032 import java.io.InvalidObjectException;
033 import java.io.ObjectInput;
034 import java.io.ObjectInputStream;
035 import java.io.ObjectOutput;
036 import java.io.Serial;
037 import java.io.Serializable;
038 import java.util.Map;
039 import java.util.Objects;
040 import java.util.function.Function;
041 import java.util.stream.Collector;
042 import java.util.stream.Stream;
043
044 import io.jenetics.Gene;
045 import io.jenetics.Genotype;
046 import io.jenetics.Optimize;
047 import io.jenetics.Phenotype;
048 import io.jenetics.internal.util.Lazy;
049 import io.jenetics.stat.MinMax;
050 import io.jenetics.util.Factory;
051 import io.jenetics.util.ISeq;
052 import 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 */
080 public 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 * populations 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 create new individuals
575 * @param maxRetries the maximal number of genotype creation 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 collectors 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 create 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 creation 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 an 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 an 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 }
|