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