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