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 G extends Gene<?, G>,
064 C 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 }
|