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 G extends Gene<?, G>,
071 C 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(_optimize) + 17;
295 hash += 31*Objects.hashCode(_population) + 17;
296 hash += 31*Objects.hashCode(_generation) + 17;
297 hash += 31*Objects.hashCode(_totalGenerations) + 17;
298 hash += 31*Objects.hashCode(_durations) + 17;
299 hash += 31*Objects.hashCode(_killCount) + 17;
300 hash += 31*Objects.hashCode(_invalidCount) + 17;
301 hash += 31*Objects.hashCode(_alterCount) + 17;
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 }
|