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