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