001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 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 */ 020package io.jenetics.engine; 021 022import static java.lang.Math.sqrt; 023import static java.lang.String.format; 024 025import java.text.NumberFormat; 026import java.time.Duration; 027import java.util.function.Consumer; 028 029import io.jenetics.Phenotype; 030import io.jenetics.stat.DoubleMomentStatistics; 031import io.jenetics.stat.IntMomentStatistics; 032import io.jenetics.stat.LongMomentStatistics; 033import 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 6.0 089 */ 090public 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 altering the population, in 172 * seconds. 173 * 174 * @return the duration statistics needed for altering the population 175 */ 176 public DoubleMomentStatistics alterDuration() { 177 return _alterDuration; 178 } 179 180 /** 181 * Return the duration statistics needed for evaluating the fitness function 182 * of the new individuals, in seconds. 183 * 184 * @return the duration statistics needed for evaluating the fitness 185 * function of the new individuals 186 */ 187 public DoubleMomentStatistics evaluationDuration() { 188 return _evaluationDuration; 189 } 190 191 /** 192 * Return the duration statistics needed for the whole evolved step, in 193 * seconds. 194 * 195 * @return the duration statistics needed for the whole evolve step 196 */ 197 public DoubleMomentStatistics evolveDuration() { 198 return _evolveDuration; 199 } 200 201 202 /* ************************************************************************* 203 * Evolution statistics 204 * ************************************************************************/ 205 206 /** 207 * Return the statistics about the killed individuals during the evolution 208 * process. 209 * 210 * @return killed individual statistics 211 */ 212 public IntMomentStatistics killed() { 213 return _killed; 214 } 215 216 /** 217 * Return the statistics about the invalid individuals during the evolution 218 * process. 219 * 220 * @return invalid individual statistics 221 */ 222 public IntMomentStatistics invalids() { 223 return _invalids; 224 } 225 226 /** 227 * Return the statistics about the altered individuals during the evolution 228 * process. 229 * 230 * @return altered individual statistics 231 */ 232 public IntMomentStatistics altered() { 233 return _altered; 234 } 235 236 /** 237 * Return the statistics about the individual's age. 238 * 239 * @return individual age statistics 240 */ 241 public LongMomentStatistics phenotypeAge() { 242 return _age; 243 } 244 245 /** 246 * Return the minimal and maximal fitness. 247 * 248 * @return minimal and maximal fitness 249 */ 250 public FitnessStatistics fitness() { 251 return _fitness; 252 } 253 254 final String cpattern = "| %22s %-51s|\n"; 255 final String spattern = "| %27s %-46s|\n"; 256 257 @Override 258 public String toString() { 259 return 260 "+---------------------------------------------------------------------------+\n" + 261 "| Time statistics |\n" + 262 "+---------------------------------------------------------------------------+\n" + 263 format(cpattern, "Selection:", d(_selectionDuration)) + 264 format(cpattern, "Altering:", d(_alterDuration)) + 265 format(cpattern, "Fitness calculation:", d(_evaluationDuration)) + 266 format(cpattern, "Overall execution:", d(_evolveDuration)) + 267 "+---------------------------------------------------------------------------+\n" + 268 "| Evolution statistics |\n" + 269 "+---------------------------------------------------------------------------+\n" + 270 format(cpattern, "Generations:", i(_altered.count())) + 271 format(cpattern, "Altered:", i(_altered)) + 272 format(cpattern, "Killed:", i(_killed)) + 273 format(cpattern, "Invalids:", i(_invalids)); 274 } 275 276 private static String d(final DoubleMomentStatistics statistics) { 277 return format( 278 "sum=%3.12f s; mean=%3.12f s", 279 statistics.sum(), statistics.mean() 280 ); 281 } 282 283 private static String i(final IntMomentStatistics statistics) { 284 final NumberFormat nf = NumberFormat.getIntegerInstance(); 285 return format( 286 "sum=%s; mean=%6.9f", 287 nf.format(statistics.sum()), statistics.mean() 288 ); 289 } 290 291 private static String i(final long value) { 292 final NumberFormat nf = NumberFormat.getIntegerInstance(); 293 return nf.format(value); 294 } 295 296 private static String p(final IntMomentStatistics statistics) { 297 final NumberFormat nf = NumberFormat.getIntegerInstance(); 298 return format( 299 "max=%s; mean=%6.6f; var=%6.6f", 300 nf.format(statistics.max()), 301 statistics.mean(), 302 statistics.variance() 303 ); 304 } 305 306 private static String p(final LongMomentStatistics statistics) { 307 final NumberFormat nf = NumberFormat.getIntegerInstance(); 308 return format( 309 "max=%s; mean=%6.6f; var=%6.6f", 310 nf.format(statistics.max()), 311 statistics.mean(), 312 statistics.variance() 313 ); 314 } 315 316 private static final class Comp< 317 C extends Comparable<? super C> 318 > 319 extends EvolutionStatistics<C, MinMax<C>> 320 { 321 private Comp() { 322 _fitness = MinMax.of(); 323 } 324 325 @Override 326 public void accept(final EvolutionResult<?, C> result) { 327 if (_fitness.max() == null) { 328 _fitness = MinMax.of(result.optimize().ascending()); 329 } 330 331 super.accept(result); 332 } 333 334 @Override 335 void accept(final Phenotype<?, C> pt, final long generation) { 336 super.accept(pt, generation); 337 _fitness.accept(pt.fitness()); 338 } 339 340 @Override 341 public String toString() { 342 return super.toString() + 343 "+---------------------------------------------------------------------------+\n" + 344 "| Population statistics |\n" + 345 "+---------------------------------------------------------------------------+\n" + 346 format(cpattern, "Age:", p(_age)) + 347 format(cpattern, "Fitness", "") + 348 format(spattern, "min =", _fitness.min()) + 349 format(spattern, "max =", _fitness.max()) + 350 "+---------------------------------------------------------------------------+"; 351 } 352 } 353 354 private static final class Num<N extends Number & Comparable<? super N>> 355 extends EvolutionStatistics<N, DoubleMomentStatistics> 356 { 357 private Num() { 358 _fitness = new DoubleMomentStatistics(); 359 } 360 361 @Override 362 void accept(final Phenotype<?, N> pt, final long generation) { 363 super.accept(pt, generation); 364 _fitness.accept(pt.fitness().doubleValue()); 365 } 366 367 @Override 368 public String toString() { 369 return super.toString() + 370 "+---------------------------------------------------------------------------+\n" + 371 "| Population statistics |\n" + 372 "+---------------------------------------------------------------------------+\n" + 373 format(cpattern, "Age:", p(_age)) + 374 format(cpattern, "Fitness:", "") + 375 format(spattern, "min =", d(_fitness.min())) + 376 format(spattern, "max =", d(_fitness.max())) + 377 format(spattern, "mean =", d(_fitness.mean())) + 378 format(spattern, "var =", d(_fitness.variance())) + 379 format(spattern, "std =", d(sqrt(_fitness.variance()))) + 380 "+---------------------------------------------------------------------------+"; 381 } 382 383 private static String d(final double value) { 384 return format("%3.12f", value); 385 } 386 } 387 388 public static <C extends Comparable<? super C>> 389 EvolutionStatistics<C, MinMax<C>> ofComparable() { 390 return new Comp<>(); 391 } 392 393 public static <N extends Number & Comparable<? super N>> 394 EvolutionStatistics<N, DoubleMomentStatistics> ofNumber() { 395 return new Num<>(); 396 } 397 398}