001 /*
002 * Java Genetic Algorithm Library (jenetics-5.2.0).
003 * Copyright (c) 2007-2020 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@gmail.com)
019 */
020 package io.jenetics.engine;
021
022 import static java.lang.Math.sqrt;
023 import static java.lang.String.format;
024
025 import java.text.NumberFormat;
026 import java.time.Duration;
027 import java.util.function.Consumer;
028
029 import io.jenetics.Phenotype;
030 import io.jenetics.stat.DoubleMomentStatistics;
031 import io.jenetics.stat.IntMomentStatistics;
032 import io.jenetics.stat.LongMomentStatistics;
033 import io.jenetics.stat.MinMax;
034
035 /**
036 * This class can be used to gather additional statistic information of an
037 * evolution process. The additional information can be useful during the
038 * development phase of the GA or while testing the GA's performance. The
039 * following example shows how to integrate the <i>statistics</i> object into
040 * your evolution <i>stream</i>.
041 *
042 * <pre>{@code
043 * final Engine<DoubleGene, Double> engine = ...
044 * final EvolutionStatistics<Double, DoubleMomentStatistics> statistics =
045 * EvolutionStatistics.ofNumber();
046 *
047 * final Phenotype<DoubleGene, Double> result = engine.stream()
048 * .limit(bySteadyFitness(7))
049 * .limit(100)
050 * .peek(statistics)
051 * .collect(toBestPhenotype());
052 *
053 * System.println(statistics);
054 * }</pre>
055 *
056 * <b>Example output</b>
057 *
058 * <pre>{@code
059 * +---------------------------------------------------------------------------+
060 * | Time statistics |
061 * +---------------------------------------------------------------------------+
062 * | Selection: sum=0.046538278000 s; mean=0.003878189833 s |
063 * | Altering: sum=0.086155457000 s; mean=0.007179621417 s |
064 * | Fitness calculation: sum=0.022901606000 s; mean=0.001908467167 s |
065 * | Overall execution: sum=0.147298067000 s; mean=0.012274838917 s |
066 * +---------------------------------------------------------------------------+
067 * | Evolution statistics |
068 * +---------------------------------------------------------------------------+
069 * | Generations: 12 |
070 * | Altered: sum=7,331; mean=610.916666667 |
071 * | Killed: sum=0; mean=0.000000000 |
072 * | Invalids: sum=0; mean=0.000000000 |
073 * +---------------------------------------------------------------------------+
074 * | Population statistics |
075 * +---------------------------------------------------------------------------+
076 * | Age: max=11; mean=1.951000; var=5.545190 |
077 * | Fitness: |
078 * | min = 0.000000000000 |
079 * | max = 481.748227114537 |
080 * | mean = 384.430345078660 |
081 * | var = 13006.132537301528 |
082 * | std = 114.044432 |
083 * +---------------------------------------------------------------------------+
084 * }</pre>
085 *
086 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
087 * @since 3.0
088 * @version 5.2
089 */
090 public abstract class EvolutionStatistics<
091 C extends Comparable<? super C>,
092 FitnessStatistics
093 >
094 implements Consumer<EvolutionResult<?, C>>
095 {
096
097 // The duration statistics values.
098 private final DoubleMomentStatistics
099 _selectionDuration = new DoubleMomentStatistics();
100 private final DoubleMomentStatistics
101 _alterDuration = new DoubleMomentStatistics();
102 private final DoubleMomentStatistics
103 _evaluationDuration = new DoubleMomentStatistics();
104 private final DoubleMomentStatistics
105 _evolveDuration = new DoubleMomentStatistics();
106
107 // The evolution statistics values.
108 private final IntMomentStatistics _killed = new IntMomentStatistics();
109 private final IntMomentStatistics _invalids = new IntMomentStatistics();
110 private final IntMomentStatistics _altered = new IntMomentStatistics();
111
112 // The population statistics values.
113 final LongMomentStatistics _age = new LongMomentStatistics();
114 FitnessStatistics _fitness = null;
115
116 EvolutionStatistics() {
117 }
118
119 @Override
120 public void accept(final EvolutionResult<?, C> result) {
121 accept(result.durations());
122
123 _killed.accept(result.killCount());
124 _invalids.accept(result.invalidCount());
125 _altered.accept(result.alterCount());
126
127 result.population()
128 .forEach(pt -> accept(pt, result.generation()));
129 }
130
131 void accept(final Phenotype<?, C> pt, final long generation) {
132 _age.accept(pt.age(generation));
133 }
134
135 // Calculate duration statistics
136 private void accept(final EvolutionDurations durations) {
137 final double selection =
138 toSeconds(durations.offspringSelectionDuration()) +
139 toSeconds(durations.survivorsSelectionDuration());
140 final double alter =
141 toSeconds(durations.offspringAlterDuration()) +
142 toSeconds(durations.offspringFilterDuration());
143
144 _selectionDuration.accept(selection);
145 _alterDuration.accept(alter);
146 _evaluationDuration
147 .accept(toSeconds(durations.evaluationDuration()));
148 _evolveDuration
149 .accept(toSeconds(durations.evolveDuration()));
150 }
151
152 private static double toSeconds(final Duration duration) {
153 return duration.toNanos()/1_000_000_000.0;
154 }
155
156 /* *************************************************************************
157 * Evaluation timing statistics
158 * ************************************************************************/
159
160 /**
161 * Return the duration statistics needed for selecting the population, in
162 * seconds.
163 *
164 * @return the duration statistics needed for selecting the population
165 */
166 public DoubleMomentStatistics selectionDuration() {
167 return _selectionDuration;
168 }
169
170 /**
171 * Return the duration statistics needed for selecting the population, in
172 * seconds.
173 *
174 * @return the duration statistics needed for selecting the population
175 * @deprecated Use {@link #selectionDuration()} instead
176 */
177 @Deprecated
178 public DoubleMomentStatistics getSelectionDuration() {
179 return _selectionDuration;
180 }
181
182 /**
183 * Return the duration statistics needed for altering the population, in
184 * seconds.
185 *
186 * @return the duration statistics needed for altering the population
187 */
188 public DoubleMomentStatistics alterDuration() {
189 return _alterDuration;
190 }
191
192 /**
193 * Return the duration statistics needed for altering the population, in
194 * seconds.
195 *
196 * @return the duration statistics needed for altering the population
197 * @deprecated Use {@link #alterDuration()} instead
198 */
199 @Deprecated
200 public DoubleMomentStatistics getAlterDuration() {
201 return _alterDuration;
202 }
203
204 /**
205 * Return the duration statistics needed for evaluating the fitness function
206 * of the new individuals, in seconds.
207 *
208 * @return the duration statistics needed for evaluating the fitness
209 * function of the new individuals
210 */
211 public DoubleMomentStatistics evaluationDuration() {
212 return _evaluationDuration;
213 }
214
215 /**
216 * Return the duration statistics needed for evaluating the fitness function
217 * of the new individuals, in seconds.
218 *
219 * @return the duration statistics needed for evaluating the fitness
220 * function of the new individuals
221 * @deprecated Use {@link #evaluationDuration()} instead
222 */
223 @Deprecated
224 public DoubleMomentStatistics getEvaluationDuration() {
225 return _evaluationDuration;
226 }
227
228 /**
229 * Return the duration statistics needed for the whole evolve step, in
230 * seconds.
231 *
232 * @return the duration statistics needed for the whole evolve step
233 */
234 public DoubleMomentStatistics evolveDuration() {
235 return _evolveDuration;
236 }
237
238 /**
239 * Return the duration statistics needed for the whole evolve step, in
240 * seconds.
241 *
242 * @return the duration statistics needed for the whole evolve step
243 * @deprecated Use {@link #evaluationDuration()} instead
244 */
245 @Deprecated
246 public DoubleMomentStatistics getEvolveDuration() {
247 return _evolveDuration;
248 }
249
250
251 /* *************************************************************************
252 * Evolution statistics
253 * ************************************************************************/
254
255 /**
256 * Return the statistics about the killed individuals during the evolution
257 * process.
258 *
259 * @return killed individual statistics
260 */
261 public IntMomentStatistics killed() {
262 return _killed;
263 }
264
265 /**
266 * Return the statistics about the killed individuals during the evolution
267 * process.
268 *
269 * @return killed individual statistics
270 * @deprecated Use {@link #killed()} instead
271 */
272 @Deprecated
273 public IntMomentStatistics getKilled() {
274 return _killed;
275 }
276
277 /**
278 * Return the statistics about the invalid individuals during the evolution
279 * process.
280 *
281 * @return invalid individual statistics
282 */
283 public IntMomentStatistics invalids() {
284 return _invalids;
285 }
286
287 /**
288 * Return the statistics about the invalid individuals during the evolution
289 * process.
290 *
291 * @return invalid individual statistics
292 * @deprecated Use {@link #invalids()} instead
293 */
294 @Deprecated
295 public IntMomentStatistics getInvalids() {
296 return _invalids;
297 }
298
299 /**
300 * Return the statistics about the altered individuals during the evolution
301 * process.
302 *
303 * @return altered individual statistics
304 */
305 public IntMomentStatistics altered() {
306 return _altered;
307 }
308
309 /**
310 * Return the statistics about the altered individuals during the evolution
311 * process.
312 *
313 * @return altered individual statistics
314 * @deprecated Use {@link #altered()} instead
315 */
316 @Deprecated
317 public IntMomentStatistics getAltered() {
318 return _altered;
319 }
320
321 /**
322 * Return the statistics about the individuals age.
323 *
324 * @return individual age statistics
325 */
326 public LongMomentStatistics phenotypeAge() {
327 return _age;
328 }
329
330 /**
331 * Return the statistics about the individuals age.
332 *
333 * @return individual age statistics
334 * @deprecated Use {@link #phenotypeAge()} instead
335 */
336 @Deprecated
337 public LongMomentStatistics getPhenotypeAge() {
338 return _age;
339 }
340
341 /**
342 * Return the minimal and maximal fitness.
343 *
344 * @return minimal and maximal fitness
345 */
346 public FitnessStatistics fitness() {
347 return _fitness;
348 }
349
350 /**
351 * Return the minimal and maximal fitness.
352 *
353 * @return minimal and maximal fitness
354 * @deprecated Use {@link #fitness()} instead
355 */
356 @Deprecated
357 public FitnessStatistics getFitness() {
358 return _fitness;
359 }
360
361 final String cpattern = "| %22s %-51s|\n";
362 final String spattern = "| %27s %-46s|\n";
363
364 @Override
365 public String toString() {
366 return
367 "+---------------------------------------------------------------------------+\n" +
368 "| Time statistics |\n" +
369 "+---------------------------------------------------------------------------+\n" +
370 format(cpattern, "Selection:", d(_selectionDuration)) +
371 format(cpattern, "Altering:", d(_alterDuration)) +
372 format(cpattern, "Fitness calculation:", d(_evaluationDuration)) +
373 format(cpattern, "Overall execution:", d(_evolveDuration)) +
374 "+---------------------------------------------------------------------------+\n" +
375 "| Evolution statistics |\n" +
376 "+---------------------------------------------------------------------------+\n" +
377 format(cpattern, "Generations:", i(_altered.count())) +
378 format(cpattern, "Altered:", i(_altered)) +
379 format(cpattern, "Killed:", i(_killed)) +
380 format(cpattern, "Invalids:", i(_invalids));
381 }
382
383 private static String d(final DoubleMomentStatistics statistics) {
384 return format(
385 "sum=%3.12f s; mean=%3.12f s",
386 statistics.sum(), statistics.mean()
387 );
388 }
389
390 private static String i(final IntMomentStatistics statistics) {
391 final NumberFormat nf = NumberFormat.getIntegerInstance();
392 return format(
393 "sum=%s; mean=%6.9f",
394 nf.format(statistics.sum()), statistics.mean()
395 );
396 }
397
398 private static String i(final long value) {
399 final NumberFormat nf = NumberFormat.getIntegerInstance();
400 return nf.format(value);
401 }
402
403 private static String p(final IntMomentStatistics statistics) {
404 final NumberFormat nf = NumberFormat.getIntegerInstance();
405 return format(
406 "max=%s; mean=%6.6f; var=%6.6f",
407 nf.format(statistics.max()),
408 statistics.mean(),
409 statistics.variance()
410 );
411 }
412
413 private static String p(final LongMomentStatistics statistics) {
414 final NumberFormat nf = NumberFormat.getIntegerInstance();
415 return format(
416 "max=%s; mean=%6.6f; var=%6.6f",
417 nf.format(statistics.max()),
418 statistics.mean(),
419 statistics.variance()
420 );
421 }
422
423 private static final class Comp<
424 C extends Comparable<? super C>
425 >
426 extends EvolutionStatistics<C, MinMax<C>>
427 {
428 private Comp() {
429 _fitness = MinMax.of();
430 }
431
432 @Override
433 public void accept(final EvolutionResult<?, C> result) {
434 if (_fitness.max() == null) {
435 _fitness = MinMax.of(result.optimize().ascending());
436 }
437
438 super.accept(result);
439 }
440
441 @Override
442 void accept(final Phenotype<?, C> pt, final long generation) {
443 super.accept(pt, generation);
444 _fitness.accept(pt.fitness());
445 }
446
447 @Override
448 public String toString() {
449 return super.toString() +
450 "+---------------------------------------------------------------------------+\n" +
451 "| Population statistics |\n" +
452 "+---------------------------------------------------------------------------+\n" +
453 format(cpattern, "Age:", p(_age)) +
454 format(cpattern, "Fitness", "") +
455 format(spattern, "min =", _fitness.min()) +
456 format(spattern, "max =", _fitness.max()) +
457 "+---------------------------------------------------------------------------+";
458 }
459 }
460
461 private static final class Num<N extends Number & Comparable<? super N>>
462 extends EvolutionStatistics<N, DoubleMomentStatistics>
463 {
464 private Num() {
465 _fitness = new DoubleMomentStatistics();
466 }
467
468 @Override
469 void accept(final Phenotype<?, N> pt, final long generation) {
470 super.accept(pt, generation);
471 _fitness.accept(pt.fitness().doubleValue());
472 }
473
474 @Override
475 public String toString() {
476 return super.toString() +
477 "+---------------------------------------------------------------------------+\n" +
478 "| Population statistics |\n" +
479 "+---------------------------------------------------------------------------+\n" +
480 format(cpattern, "Age:", p(_age)) +
481 format(cpattern, "Fitness:", "") +
482 format(spattern, "min =", d(_fitness.min())) +
483 format(spattern, "max =", d(_fitness.max())) +
484 format(spattern, "mean =", d(_fitness.mean())) +
485 format(spattern, "var =", d(_fitness.variance())) +
486 format(spattern, "std =", d(sqrt(_fitness.variance()))) +
487 "+---------------------------------------------------------------------------+";
488 }
489
490 private static String d(final double value) {
491 return format("%3.12f", value);
492 }
493 }
494
495 public static <C extends Comparable<? super C>>
496 EvolutionStatistics<C, MinMax<C>> ofComparable() {
497 return new Comp<>();
498 }
499
500 public static <N extends Number & Comparable<? super N>>
501 EvolutionStatistics<N, DoubleMomentStatistics> ofNumber() {
502 return new Num<>();
503 }
504
505 }
|