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