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