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