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