EvolutionResult.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.9.0).
003  * Copyright (c) 2007-2017 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@gmx.at)
019  */
020 package org.jenetics.engine;
021 
022 import static java.util.Objects.requireNonNull;
023 
024 import java.io.Serializable;
025 import java.util.List;
026 import java.util.Objects;
027 import java.util.function.Function;
028 import java.util.stream.Collector;
029 import java.util.stream.Collectors;
030 
031 import org.jenetics.internal.util.Lazy;
032 
033 import org.jenetics.Gene;
034 import org.jenetics.Genotype;
035 import org.jenetics.Optimize;
036 import org.jenetics.Phenotype;
037 import org.jenetics.Population;
038 import org.jenetics.stat.MinMax;
039 
040 /**
041  * Represents a state of the GA after an evolution step. It also represents the
042  * final state of an evolution process and can be created with an appropriate
043  * collector:
044  <pre>{@code
045  * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
046  * final EvolutionResult<EnumGene<Point>, Double> result = Engine.builder(tsm)
047  *     .optimize(Optimize.MINIMUM).build()
048  *     .stream()
049  *     .limit(100)
050  *     .collect(EvolutionResult.toBestEvolutionResult());
051  * }</pre>
052  *
053  @see EvolutionStart
054  @see Engine
055  *
056  @param <G> the gene type
057  @param <C> the fitness type
058  *
059  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
060  @since 3.0
061  @version 3.9
062  */
063 public final class EvolutionResult<
064     extends Gene<?, G>,
065     extends Comparable<? super C>
066 >
067     implements Comparable<EvolutionResult<G, C>>, Serializable
068 {
069     private static final long serialVersionUID = 1L;
070 
071     private final Optimize _optimize;
072     private final Population<G, C> _population;
073     private final long _generation;
074     private final long _totalGenerations;
075 
076     private final EvolutionDurations _durations;
077     private final int _killCount;
078     private final int _invalidCount;
079     private final int _alterCount;
080 
081     private final Lazy<Phenotype<G, C>> _best;
082     private final Lazy<Phenotype<G, C>> _worst;
083 
084     private EvolutionResult(
085         final Optimize optimize,
086         final Population<G, C> population,
087         final long generation,
088         final long totalGenerations,
089         final EvolutionDurations durations,
090         final int killCount,
091         final int invalidCount,
092         final int alterCount
093     ) {
094         _optimize = requireNonNull(optimize);
095         _population = requireNonNull(population).copy();
096         _generation = generation;
097         _totalGenerations = totalGenerations;
098         _durations = requireNonNull(durations);
099         _killCount = killCount;
100         _invalidCount = invalidCount;
101         _alterCount = alterCount;
102 
103         _best = Lazy.of(() -> _population.stream()
104             .max(_optimize.ascending())
105             .orElse(null)
106         );
107 
108         _worst = Lazy.of(() -> _population.stream()
109             .min(_optimize.ascending())
110             .orElse(null)
111         );
112     }
113 
114     /**
115      * Return the optimization strategy used.
116      *
117      @return the optimization strategy used
118      */
119     public Optimize getOptimize() {
120         return _optimize;
121     }
122 
123     /**
124      * Return the population after the evolution step.
125      *
126      @return the population after the evolution step
127      */
128     public Population<G, C> getPopulation() {
129         return _population.copy();
130     }
131 
132     /**
133      * Return the current list of genotypes of this evolution result.
134      *
135      @since 3.9
136      *
137      @return the list of genotypes of this evolution result.
138      */
139     public List<Genotype<G>> getGenotypes() {
140         return _population.stream()
141             .map(Phenotype::getGenotype)
142             .collect(Collectors.toList());
143     }
144 
145     /**
146      * The current generation.
147      *
148      @return the current generation
149      */
150     public long getGeneration() {
151         return _generation;
152     }
153 
154     /**
155      * Return the generation count evaluated so far.
156      *
157      @return the total number of generations evaluated so far
158      */
159     public long getTotalGenerations() {
160         return _totalGenerations;
161     }
162 
163     /**
164      * Return the timing (meta) information of the evolution step.
165      *
166      @return the timing (meta) information of the evolution step
167      */
168     public EvolutionDurations getDurations() {
169         return _durations;
170     }
171 
172     /**
173      * Return the number of killed individuals.
174      *
175      @return the number of killed individuals
176      */
177     public int getKillCount() {
178         return _killCount;
179     }
180 
181     /**
182      * Return the number of invalid individuals.
183      *
184      @return the number of invalid individuals
185      */
186     public int getInvalidCount() {
187         return _invalidCount;
188     }
189 
190     /**
191      * The number of altered individuals.
192      *
193      @return the number of altered individuals
194      */
195     public int getAlterCount() {
196         return _alterCount;
197     }
198 
199     /**
200      * Return the best {@code Phenotype} of the result population.
201      *
202      @return the best {@code Phenotype} of the result population
203      */
204     public Phenotype<G, C> getBestPhenotype() {
205         return _best.get();
206     }
207 
208     /**
209      * Return the worst {@code Phenotype} of the result population.
210      *
211      @return the worst {@code Phenotype} of the result population
212      */
213     public Phenotype<G, C> getWorstPhenotype() {
214         return _worst.get();
215     }
216 
217     /**
218      * Return the best population fitness.
219      *
220      @return The best population fitness.
221      */
222     public C getBestFitness() {
223         return _best.get() != null ? _best.get().getFitness() null;
224     }
225 
226     /**
227      * Return the worst population fitness.
228      *
229      @return The worst population fitness.
230      */
231     public C getWorstFitness() {
232         return _worst.get() != null ? _worst.get().getFitness() null;
233     }
234 
235     /**
236      * Return the next evolution start object with the current population and
237      * the incremented generation.
238      *
239      @return the next evolution start object
240      */
241     EvolutionStart<G, C> next() {
242         return EvolutionStart.of(_population, _generation + 1);
243     }
244 
245     /**
246      * Compare {@code this} evolution result with another one, according the
247      * populations best individual.
248      *
249      @param other the other evolution result to compare
250      @return  a negative integer, zero, or a positive integer as this result
251      *          is less than, equal to, or greater than the specified result.
252      */
253     @Override
254     public int compareTo(final EvolutionResult<G, C> other) {
255         return _optimize.compare(_best.get(), other._best.get());
256     }
257 
258     private EvolutionResult<G, C> withTotalGenerations(final long total) {
259         return of(
260             _optimize,
261             _population,
262             _generation,
263             total,
264             _durations,
265             _killCount,
266             _invalidCount,
267             _alterCount
268         );
269     }
270 
271     @Override
272     public int hashCode() {
273         int hash = 17;
274         hash += 31*Objects.hashCode(_optimize17;
275         hash += 31*Objects.hashCode(_population17;
276         hash += 31*Objects.hashCode(_generation17;
277         hash += 31*Objects.hashCode(_totalGenerations17;
278         hash += 31*Objects.hashCode(_durations17;
279         hash += 31*Objects.hashCode(_killCount17;
280         hash += 31*Objects.hashCode(_invalidCount17;
281         hash += 31*Objects.hashCode(_alterCount17;
282         hash += 31*Objects.hashCode(getBestFitness()) 17;
283         return hash;
284     }
285 
286     @Override
287     public boolean equals(final Object obj) {
288         return obj instanceof EvolutionResult<?, ?> &&
289             Objects.equals(_optimize,
290                 ((EvolutionResult<?, ?>)obj)._optimize&&
291             Objects.equals(_population,
292                 ((EvolutionResult<?, ?>)obj)._population&&
293             Objects.equals(_generation,
294                 ((EvolutionResult<?, ?>)obj)._generation&&
295             Objects.equals(_totalGenerations,
296                 ((EvolutionResult<?, ?>)obj)._totalGenerations&&
297             Objects.equals(_durations,
298                 ((EvolutionResult<?, ?>)obj)._durations&&
299             Objects.equals(_killCount,
300                 ((EvolutionResult<?, ?>)obj)._killCount&&
301             Objects.equals(_invalidCount,
302                 ((EvolutionResult<?, ?>)obj)._invalidCount&&
303             Objects.equals(_alterCount,
304                 ((EvolutionResult<?, ?>)obj)._alterCount&&
305             Objects.equals(getBestFitness(),
306                 ((EvolutionResult<?, ?>)obj).getBestFitness());
307     }
308 
309 
310     /* *************************************************************************
311      *  Some static collector/factory methods.
312      * ************************************************************************/
313 
314     /**
315      * Return a collector which collects the best result of an evolution stream.
316      *
317      <pre>{@code
318      * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
319      * final EvolutionResult<EnumGene<Point>, Double> result = Engine.builder(tsm)
320      *     .optimize(Optimize.MINIMUM).build()
321      *     .stream()
322      *     .limit(100)
323      *     .collect(EvolutionResult.toBestEvolutionResult());
324      * }</pre>
325      *
326      * If the collected {@link EvolutionStream} is empty, the collector returns
327      <b>{@code null}</b>.
328      *
329      @param <G> the gene type
330      @param <C> the fitness type
331      @return a collector which collects the best result of an evolution stream
332      */
333     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
334     Collector<EvolutionResult<G, C>, ?, EvolutionResult<G, C>>
335     toBestEvolutionResult() {
336         return Collector.of(
337             MinMax::<EvolutionResult<G, C>>of,
338             MinMax::accept,
339             MinMax::combine,
340             mm -> mm.getMax() != null
341                 ? mm.getMax().withTotalGenerations(mm.getCount())
342                 null
343         );
344     }
345 
346     /**
347      * Return a collector which collects the best phenotype of an evolution
348      * stream.
349      *
350      <pre>{@code
351      * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
352      * final Phenotype<EnumGene<Point>, Double> result = Engine.builder(tsm)
353      *     .optimize(Optimize.MINIMUM).build()
354      *     .stream()
355      *     .limit(100)
356      *     .collect(EvolutionResult.toBestPhenotype());
357      * }</pre>
358      *
359      * If the collected {@link EvolutionStream} is empty, the collector returns
360      <b>{@code null}</b>.
361      *
362      @param <G> the gene type
363      @param <C> the fitness type
364      @return a collector which collects the best phenotype of an evolution
365      *         stream
366      */
367     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
368     Collector<EvolutionResult<G, C>, ?, Phenotype<G, C>>
369     toBestPhenotype() {
370         return Collector.of(
371             MinMax::<EvolutionResult<G, C>>of,
372             MinMax::accept,
373             MinMax::combine,
374             mm -> mm.getMax() != null
375                 ? mm.getMax().getBestPhenotype()
376                 null
377         );
378     }
379 
380     /**
381      * Return a collector which collects the best genotype of an evolution
382      * stream.
383      *
384      <pre>{@code
385      * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
386      * final Genotype<EnumGene<Point>> result = Engine.builder(tsm)
387      *     .optimize(Optimize.MINIMUM).build()
388      *     .stream()
389      *     .limit(100)
390      *     .collect(EvolutionResult.toBestGenotype());
391      * }</pre>
392      *
393      * If the collected {@link EvolutionStream} is empty, the collector returns
394      <b>{@code null}</b>.
395      *
396      @param <G> the gene type
397      @param <C> the fitness type
398      @return a collector which collects the best genotype of an evolution
399      *         stream
400      */
401     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
402     Collector<EvolutionResult<G, C>, ?, Genotype<G>>
403     toBestGenotype() {
404         return Collector.of(
405             MinMax::<EvolutionResult<G, C>>of,
406             MinMax::accept,
407             MinMax::combine,
408             mm -> mm.getMax() != null
409                 ? mm.getMax().getBestPhenotype() != null
410                     ? mm.getMax().getBestPhenotype().getGenotype()
411                     null
412                 null
413         );
414     }
415 
416     /**
417      * Return a collector which collects the best <em>result</em> (in the native
418      * problem space).
419      *
420      <pre>{@code
421      * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
422      * final ISeq<Point> route = Engine.builder(tsm)
423      *     .optimize(Optimize.MINIMUM).build()
424      *     .stream()
425      *     .limit(100)
426      *     .collect(EvolutionResult.toBestResult(tsm.codec().decoder()));
427      * }</pre>
428      *
429      * If the collected {@link EvolutionStream} is empty, the collector returns
430      <b>{@code null}</b>.
431      *
432      @since 3.6
433      *
434      @param decoder the decoder which converts the {@code Genotype} into the
435      *        result of the problem space.
436      @param <T> the <em>native</em> problem result type
437      @param <G> the gene type
438      @param <C> the fitness result type
439      @return a collector which collects the best result of an evolution stream
440      @throws NullPointerException if the given {@code decoder} is {@code null}
441      */
442     public static <G extends Gene<?, G>, C extends Comparable<? super C>, T>
443     Collector<EvolutionResult<G, C>, ?, T>
444     toBestResult(final Function<Genotype<G>, T> decoder) {
445         requireNonNull(decoder);
446 
447         return Collector.of(
448             MinMax::<EvolutionResult<G, C>>of,
449             MinMax::accept,
450             MinMax::combine,
451             mm -> mm.getMax() != null
452                 ? mm.getMax().getBestPhenotype() != null
453                     ? decoder.apply(mm.getMax().getBestPhenotype().getGenotype())
454                     null
455                 null
456         );
457     }
458 
459     /**
460      * Return a collector which collects the best <em>result</em> (in the native
461      * problem space).
462      *
463      <pre>{@code
464      * final Problem<ISeq<Point>, EnumGene<Point>, Double> tsm = ...;
465      * final ISeq<Point> route = Engine.builder(tsm)
466      *     .optimize(Optimize.MINIMUM).build()
467      *     .stream()
468      *     .limit(100)
469      *     .collect(EvolutionResult.toBestResult(tsm.codec()));
470      * }</pre>
471      *
472      * If the collected {@link EvolutionStream} is empty, the collector returns
473      <b>{@code null}</b>.
474      *
475      @since 3.6
476      *
477      @param codec the problem decoder
478      @param <T> the <em>native</em> problem result type
479      @param <G> the gene type
480      @param <C> the fitness result type
481      @return a collector which collects the best result of an evolution stream
482      @throws NullPointerException if the given {@code codec} is {@code null}
483      */
484     public static <G extends Gene<?, G>, C extends Comparable<? super C>, T>
485     Collector<EvolutionResult<G, C>, ?, T>
486     toBestResult(final Codec<T, G> codec) {
487         return toBestResult(codec.decoder());
488     }
489 
490     /**
491      * Return an new {@code EvolutionResult} object with the given values.
492      *
493      @param optimize the optimization strategy used
494      @param population the population after the evolution step
495      @param generation the current generation
496      @param totalGenerations the overall number of generations
497      @param durations the timing (meta) information
498      @param killCount the number of individuals which has been killed
499      @param invalidCount the number of individuals which has been removed as
500      *        invalid
501      @param alterCount the number of individuals which has been altered
502      @param <G> the gene type
503      @param <C> the fitness type
504      @return an new evolution result object
505      @throws java.lang.NullPointerException if one of the parameters is
506      *         {@code null}
507      */
508     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
509     EvolutionResult<G, C> of(
510         final Optimize optimize,
511         final Population<G, C> population,
512         final long generation,
513         final long totalGenerations,
514         final EvolutionDurations durations,
515         final int killCount,
516         final int invalidCount,
517         final int alterCount
518     ) {
519         return new EvolutionResult<>(
520             optimize,
521             population,
522             generation,
523             totalGenerations,
524             durations,
525             killCount,
526             invalidCount,
527             alterCount
528         );
529     }
530 
531     /**
532      * Return an new {@code EvolutionResult} object with the given values.
533      *
534      @param optimize the optimization strategy used
535      @param population the population after the evolution step
536      @param generation the current generation
537      @param durations the timing (meta) information
538      @param killCount the number of individuals which has been killed
539      @param invalidCount the number of individuals which has been removed as
540      *        invalid
541      @param alterCount the number of individuals which has been altered
542      @param <G> the gene type
543      @param <C> the fitness type
544      @return an new evolution result object
545      @throws java.lang.NullPointerException if one of the parameters is
546      *         {@code null}
547      */
548     public static <G extends Gene<?, G>, C extends Comparable<? super C>>
549     EvolutionResult<G, C> of(
550         final Optimize optimize,
551         final Population<G, C> population,
552         final long generation,
553         final EvolutionDurations durations,
554         final int killCount,
555         final int invalidCount,
556         final int alterCount
557     ) {
558         return new EvolutionResult<>(
559             optimize,
560             population,
561             generation,
562             generation,
563             durations,
564             killCount,
565             invalidCount,
566             alterCount
567         );
568     }
569 
570 }