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