001 /*
002 * Java Genetic Algorithm Library (jenetics-5.1.0).
003 * Copyright (c) 2007-2019 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.internal.util.Hashes.hash;
025
026 import java.io.Serializable;
027 import java.util.Map;
028 import java.util.Objects;
029 import java.util.function.Function;
030 import java.util.function.UnaryOperator;
031 import java.util.stream.Collector;
032 import java.util.stream.Stream;
033
034 import io.jenetics.Gene;
035 import io.jenetics.Genotype;
036 import io.jenetics.Optimize;
037 import io.jenetics.Phenotype;
038 import io.jenetics.internal.util.Lazy;
039 import io.jenetics.stat.MinMax;
040 import io.jenetics.util.Factory;
041 import io.jenetics.util.ISeq;
042 import io.jenetics.util.Seq;
043
044 /**
045 * Represents a state of the GA after an evolution step. It also represents the
046 * final state of an evolution process and can be created with an appropriate
047 * collector:
048 * <pre>{@code
049 * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
050 * final EvolutionResult<EnumGene<Point>, Double> result = Engine.builder(tsm)
051 * .optimize(Optimize.MINIMUM).build()
052 * .stream()
053 * .limit(100)
054 * .collect(EvolutionResult.toBestEvolutionResult());
055 * }</pre>
056 *
057 * @see EvolutionStart
058 * @see Engine
059 *
060 * @param <G> the gene type
061 * @param <C> the fitness type
062 *
063 * @implNote
064 * This class is immutable and thread-safe.
065 *
066 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
067 * @since 3.0
068 * @version 4.0
069 */
070 public final class EvolutionResult<
071 G extends Gene<?, G>,
072 C extends Comparable<? super C>
073 >
074 implements Comparable<EvolutionResult<G, C>>, Serializable
075 {
076 private static final long serialVersionUID = 1L;
077
078 private final Optimize _optimize;
079 private final ISeq<Phenotype<G, C>> _population;
080 private final long _generation;
081 private final long _totalGenerations;
082
083 private final EvolutionDurations _durations;
084 private final int _killCount;
085 private final int _invalidCount;
086 private final int _alterCount;
087
088 private final Lazy<Phenotype<G, C>> _best;
089 private final Lazy<Phenotype<G, C>> _worst;
090
091 private EvolutionResult(
092 final Optimize optimize,
093 final ISeq<Phenotype<G, C>> population,
094 final long generation,
095 final long totalGenerations,
096 final EvolutionDurations durations,
097 final int killCount,
098 final int invalidCount,
099 final int alterCount
100 ) {
101 _optimize = requireNonNull(optimize);
102 _population = requireNonNull(population);
103 _generation = generation;
104 _totalGenerations = totalGenerations;
105 _durations = requireNonNull(durations);
106 _killCount = killCount;
107 _invalidCount = invalidCount;
108 _alterCount = alterCount;
109
110 _best = Lazy.of(() -> _population.stream()
111 .max(_optimize.ascending())
112 .orElse(null)
113 );
114
115 _worst = Lazy.of(() -> _population.stream()
116 .min(_optimize.ascending())
117 .orElse(null)
118 );
119 }
120
121 /**
122 * Return the optimization strategy used.
123 *
124 * @return the optimization strategy used
125 */
126 public Optimize getOptimize() {
127 return _optimize;
128 }
129
130 /**
131 * Return the population after the evolution step.
132 *
133 * @return the population after the evolution step
134 */
135 public ISeq<Phenotype<G, C>> getPopulation() {
136 return _population;
137 }
138
139 /**
140 * Return the current list of genotypes of this evolution result.
141 *
142 * @since 3.9
143 *
144 * @return the list of genotypes of this evolution result.
145 */
146 public ISeq<Genotype<G>> getGenotypes() {
147 return _population.stream()
148 .map(Phenotype::getGenotype)
149 .collect(ISeq.toISeq());
150 }
151
152 /**
153 * The current generation.
154 *
155 * @return the current generation
156 */
157 public long getGeneration() {
158 return _generation;
159 }
160
161 /**
162 * Return the generation count evaluated so far.
163 *
164 * @return the total number of generations evaluated so far
165 */
166 public long getTotalGenerations() {
167 return _totalGenerations;
168 }
169
170 /**
171 * Return the timing (meta) information of the evolution step.
172 *
173 * @return the timing (meta) information of the evolution step
174 */
175 public EvolutionDurations getDurations() {
176 return _durations;
177 }
178
179 /**
180 * Return the number of killed individuals.
181 *
182 * @return the number of killed individuals
183 */
184 public int getKillCount() {
185 return _killCount;
186 }
187
188 /**
189 * Return the number of invalid individuals.
190 *
191 * @return the number of invalid individuals
192 */
193 public int getInvalidCount() {
194 return _invalidCount;
195 }
196
197 /**
198 * The number of altered individuals.
199 *
200 * @return the number of altered individuals
201 */
202 public int getAlterCount() {
203 return _alterCount;
204 }
205
206 /**
207 * Return the best {@code Phenotype} of the result population.
208 *
209 * @return the best {@code Phenotype} of the result population
210 */
211 public Phenotype<G, C> getBestPhenotype() {
212 return _best.get();
213 }
214
215 /**
216 * Return the worst {@code Phenotype} of the result population.
217 *
218 * @return the worst {@code Phenotype} of the result population
219 */
220 public Phenotype<G, C> getWorstPhenotype() {
221 return _worst.get();
222 }
223
224 /**
225 * Return the best population fitness.
226 *
227 * @return The best population fitness.
228 */
229 public C getBestFitness() {
230 return _best.get() != null
231 ? _best.get().getFitness()
232 : null;
233 }
234
235 /**
236 * Return the worst population fitness.
237 *
238 * @return The worst population fitness.
239 */
240 public C getWorstFitness() {
241 return _worst.get() != null ? _worst.get().getFitness() : null;
242 }
243
244 /**
245 * Return the next evolution start object with the current population and
246 * the incremented generation.
247 *
248 * @since 4.1
249 *
250 * @return the next evolution start object
251 */
252 public EvolutionStart<G, C> next() {
253 return EvolutionStart.of(_population, _totalGenerations + 1);
254 }
255
256 /**
257 * Return the current evolution result object as an {@code EvolutionStart}
258 * object with the current population and current total generation.
259 *
260 * @since 4.1
261 *
262 * @return the current result as evolution start
263 */
264 public EvolutionStart<G, C> toEvolutionStart() {
265 return EvolutionStart.of(_population, _totalGenerations);
266 }
267
268 /**
269 * Compare {@code this} evolution result with another one, according the
270 * populations best individual.
271 *
272 * @param other the other evolution result to compare
273 * @return a negative integer, zero, or a positive integer as this result
274 * is less than, equal to, or greater than the specified result.
275 */
276 @Override
277 public int compareTo(final EvolutionResult<G, C> other) {
278 return _optimize.compare(_best.get(), other._best.get());
279 }
280
281 private EvolutionResult<G, C> withTotalGenerations(final long total) {
282 return of(
283 _optimize,
284 _population,
285 _generation,
286 total,
287 _durations,
288 _killCount,
289 _invalidCount,
290 _alterCount
291 );
292 }
293
294 @Override
295 public int hashCode() {
296 return
297 hash(_optimize,
298 hash(_population,
299 hash(_generation,
300 hash(_totalGenerations,
301 hash(_durations,
302 hash(_killCount,
303 hash(_invalidCount,
304 hash(_alterCount))))))));
305 }
306
307 @Override
308 public boolean equals(final Object obj) {
309 return obj == this ||
310 obj instanceof EvolutionResult &&
311 Objects.equals(_optimize,
312 ((EvolutionResult)obj)._optimize) &&
313 Objects.equals(_population,
314 ((EvolutionResult)obj)._population) &&
315 Objects.equals(_generation,
316 ((EvolutionResult)obj)._generation) &&
317 Objects.equals(_totalGenerations,
318 ((EvolutionResult)obj)._totalGenerations) &&
319 Objects.equals(_durations,
320 ((EvolutionResult)obj)._durations) &&
321 Objects.equals(_killCount,
322 ((EvolutionResult)obj)._killCount) &&
323 Objects.equals(_invalidCount,
324 ((EvolutionResult)obj)._invalidCount) &&
325 Objects.equals(_alterCount,
326 ((EvolutionResult)obj)._alterCount);
327 }
328
329
330 /* *************************************************************************
331 * Some static collector/factory methods.
332 * ************************************************************************/
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(factory);
542
543 return result -> {
544 final Seq<Phenotype<G, C>> population = result.getPopulation();
545 final Seq<Genotype<G>> genotypes = result.getGenotypes();
546 final Map<Genotype<G>, Phenotype<G, C>> elements =
547 population.stream()
548 .collect(toMap(
549 Phenotype::getGenotype,
550 Function.identity(),
551 (a, b) -> a));
552
553 EvolutionResult<G, C> uniques = result;
554 if (elements.size() < population.size()) {
555 int retries = 0;
556 while (elements.size() < population.size() && retries < maxRetries) {
557 final Genotype<G> gt = factory.newInstance();
558 final Phenotype<G, C> pt = elements
559 .put(gt, Phenotype.of(gt, result.getGeneration()));
560
561 if (pt != null) {
562 ++retries;
563 }
564 }
565
566 uniques = result.with(
567 Stream.concat(elements.values().stream(), population.stream())
568 .limit(population.size())
569 .collect(ISeq.toISeq())
570 );
571 }
572
573 return uniques;
574 };
575 }
576
577 EvolutionResult<G, C> with(final ISeq<Phenotype<G, C>> population) {
578 return EvolutionResult.of(
579 getOptimize(),
580 population,
581 getGeneration(),
582 getTotalGenerations(),
583 getDurations(),
584 getKillCount(),
585 getInvalidCount(),
586 getAlterCount()
587 );
588 }
589
590 EvolutionResult<G, C> with(final EvolutionDurations durations) {
591 return EvolutionResult.of(
592 getOptimize(),
593 getPopulation(),
594 getGeneration(),
595 getTotalGenerations(),
596 durations,
597 getKillCount(),
598 getInvalidCount(),
599 getAlterCount()
600 );
601 }
602
603
604 /* *************************************************************************
605 * Some collectors and mapping functions.
606 * ************************************************************************/
607
608
609
610 /**
611 * Return a mapping function, which removes duplicate individuals from the
612 * population and replaces it with newly created one by the given genotype
613 * {@code factory}.
614 *
615 * <pre>{@code
616 * final Problem<Double, DoubleGene, Integer> problem = ...;
617 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem)
618 * .mapping(EvolutionResult.toUniquePopulation(problem.codec().encoding()))
619 * .build();
620 * final Genotype<DoubleGene> best = engine.stream()
621 * .limit(100);
622 * .collect(EvolutionResult.toBestGenotype());
623 * }</pre>
624 *
625 * @since 4.0
626 * @see Engine.Builder#mapping(Function)
627 *
628 * @param factory the genotype factory which create new individuals
629 * @param <G> the gene type
630 * @param <C> the fitness function result type
631 * @return a mapping function, which removes duplicate individuals from the
632 * population
633 * @throws NullPointerException if the given genotype {@code factory} is
634 * {@code null}
635 */
636 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
637 UnaryOperator<EvolutionResult<G, C>>
638 toUniquePopulation(final Factory<Genotype<G>> factory) {
639 return toUniquePopulation(factory, 100);
640 }
641
642 /**
643 * Return a mapping function, which removes duplicate individuals from the
644 * population and replaces it with newly created one by the existing
645 * genotype factory.
646 *
647 * <pre>{@code
648 * final Problem<Double, DoubleGene, Integer> problem = ...;
649 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem)
650 * .mapping(EvolutionResult.toUniquePopulation(10))
651 * .build();
652 * final Genotype<DoubleGene> best = engine.stream()
653 * .limit(100);
654 * .collect(EvolutionResult.toBestGenotype(5));
655 * }</pre>
656 *
657 * @since 4.0
658 * @see Engine.Builder#mapping(Function)
659 *
660 * @param maxRetries the maximal number of genotype creation tries
661 * @param <G> the gene type
662 * @param <C> the fitness function result type
663 * @return a mapping function, which removes duplicate individuals from the
664 * population
665 * @throws NullPointerException if the given genotype {@code factory} is
666 * {@code null}
667 */
668 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
669 UnaryOperator<EvolutionResult<G, C>> toUniquePopulation(final int maxRetries) {
670 return result -> {
671 final Factory<Genotype<G>> factory = result
672 .getPopulation().get(0)
673 .getGenotype();
674
675 final UnaryOperator<EvolutionResult<G, C>> unifier =
676 toUniquePopulation(factory, maxRetries);
677
678 return unifier.apply(result);
679 };
680 }
681
682 /**
683 * Return a mapping function, which removes duplicate individuals from the
684 * population and replaces it with newly created one by the existing
685 * genotype factory.
686 *
687 * <pre>{@code
688 * final Problem<Double, DoubleGene, Integer> problem = ...;
689 * final Engine<DoubleGene, Integer> engine = Engine.builder(problem)
690 * .mapping(EvolutionResult.toUniquePopulation())
691 * .build();
692 * final Genotype<DoubleGene> best = engine.stream()
693 * .limit(100);
694 * .collect(EvolutionResult.toBestGenotype());
695 * }</pre>
696 *
697 * @since 4.0
698 * @see Engine.Builder#mapping(Function)
699 *
700 * @param <G> the gene type
701 * @param <C> the fitness function result type
702 * @return a mapping function, which removes duplicate individuals from the
703 * population
704 * @throws NullPointerException if the given genotype {@code factory} is
705 * {@code null}
706 */
707 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
708 UnaryOperator<EvolutionResult<G, C>> toUniquePopulation() {
709 return result -> {
710 final Factory<Genotype<G>> factory = result
711 .getPopulation().get(0)
712 .getGenotype();
713
714 final UnaryOperator<EvolutionResult<G, C>> unifier =
715 toUniquePopulation(factory);
716
717 return unifier.apply(result);
718 };
719 }
720
721 /**
722 * Return an new {@code EvolutionResult} object with the given values.
723 *
724 * @param optimize the optimization strategy used
725 * @param population the population after the evolution step
726 * @param generation the current generation
727 * @param totalGenerations the overall number of generations
728 * @param durations the timing (meta) information
729 * @param killCount the number of individuals which has been killed
730 * @param invalidCount the number of individuals which has been removed as
731 * invalid
732 * @param alterCount the number of individuals which has been altered
733 * @param <G> the gene type
734 * @param <C> the fitness type
735 * @return an new evolution result object
736 * @throws java.lang.NullPointerException if one of the parameters is
737 * {@code null}
738 */
739 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
740 EvolutionResult<G, C> of(
741 final Optimize optimize,
742 final ISeq<Phenotype<G, C>> population,
743 final long generation,
744 final long totalGenerations,
745 final EvolutionDurations durations,
746 final int killCount,
747 final int invalidCount,
748 final int alterCount
749 ) {
750 return new EvolutionResult<>(
751 optimize,
752 population,
753 generation,
754 totalGenerations,
755 durations,
756 killCount,
757 invalidCount,
758 alterCount
759 );
760 }
761
762 /**
763 * Return an new {@code EvolutionResult} object with the given values.
764 *
765 * @param optimize the optimization strategy used
766 * @param population the population after the evolution step
767 * @param generation the current generation
768 * @param durations the timing (meta) information
769 * @param killCount the number of individuals which has been killed
770 * @param invalidCount the number of individuals which has been removed as
771 * invalid
772 * @param alterCount the number of individuals which has been altered
773 * @param <G> the gene type
774 * @param <C> the fitness type
775 * @return an new evolution result object
776 * @throws java.lang.NullPointerException if one of the parameters is
777 * {@code null}
778 */
779 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
780 EvolutionResult<G, C> of(
781 final Optimize optimize,
782 final ISeq<Phenotype<G, C>> population,
783 final long generation,
784 final EvolutionDurations durations,
785 final int killCount,
786 final int invalidCount,
787 final int alterCount
788 ) {
789 return new EvolutionResult<>(
790 optimize,
791 population,
792 generation,
793 generation,
794 durations,
795 killCount,
796 invalidCount,
797 alterCount
798 );
799 }
800
801 }
|