001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 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 * {@snippet lang="java": 042 * final Engine<DoubleGene, Double> engine = null; // @replace substring='null' replacement="..." 043 * final EvolutionStatistics<Double, DoubleMomentStatistics> statistics = 044 * EvolutionStatistics.ofNumber(); 045 * 046 * final Phenotype<DoubleGene, Double> result = engine.stream() 047 * .limit(bySteadyFitness(7)) 048 * .limit(100) 049 * .peek(statistics) 050 * .collect(toBestPhenotype()); 051 * 052 * System.println(statistics); 053 * } 054 * 055 * <b>Example output</b> 056 * 057 * <pre>{@code 058 * +---------------------------------------------------------------------------+ 059 * | Time statistics | 060 * +---------------------------------------------------------------------------+ 061 * | Selection: sum=0.046538278000 s; mean=0.003878189833 s | 062 * | Altering: sum=0.086155457000 s; mean=0.007179621417 s | 063 * | Fitness calculation: sum=0.022901606000 s; mean=0.001908467167 s | 064 * | Overall execution: sum=0.147298067000 s; mean=0.012274838917 s | 065 * +---------------------------------------------------------------------------+ 066 * | Evolution statistics | 067 * +---------------------------------------------------------------------------+ 068 * | Generations: 12 | 069 * | Altered: sum=7,331; mean=610.916666667 | 070 * | Killed: sum=0; mean=0.000000000 | 071 * | Invalids: sum=0; mean=0.000000000 | 072 * +---------------------------------------------------------------------------+ 073 * | Population statistics | 074 * +---------------------------------------------------------------------------+ 075 * | Age: max=11; mean=1.951000; var=5.545190 | 076 * | Fitness: | 077 * | min = 0.000000000000 | 078 * | max = 481.748227114537 | 079 * | mean = 384.430345078660 | 080 * | var = 13006.132537301528 | 081 * | std = 114.044432 | 082 * +---------------------------------------------------------------------------+ 083 * }</pre> 084 * 085 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 086 * @since 3.0 087 * @version 6.0 088 */ 089public abstract class EvolutionStatistics< 090 C extends Comparable<? super C>, 091 FitnessStatistics 092> 093 implements Consumer<EvolutionResult<?, C>> 094{ 095 096 // The duration statistics values. 097 private final DoubleMomentStatistics 098 _selectionDuration = new DoubleMomentStatistics(); 099 private final DoubleMomentStatistics 100 _alterDuration = new DoubleMomentStatistics(); 101 private final DoubleMomentStatistics 102 _evaluationDuration = new DoubleMomentStatistics(); 103 private final DoubleMomentStatistics 104 _evolveDuration = new DoubleMomentStatistics(); 105 106 // The evolution statistics values. 107 private final IntMomentStatistics _killed = new IntMomentStatistics(); 108 private final IntMomentStatistics _invalids = new IntMomentStatistics(); 109 private final IntMomentStatistics _altered = new IntMomentStatistics(); 110 111 // The population statistics values. 112 final LongMomentStatistics _age = new LongMomentStatistics(); 113 FitnessStatistics _fitness = null; 114 115 EvolutionStatistics() { 116 } 117 118 @Override 119 public void accept(final EvolutionResult<?, C> result) { 120 accept(result.durations()); 121 122 _killed.accept(result.killCount()); 123 _invalids.accept(result.invalidCount()); 124 _altered.accept(result.alterCount()); 125 126 result.population() 127 .forEach(pt -> accept(pt, result.generation())); 128 } 129 130 void accept(final Phenotype<?, C> pt, final long generation) { 131 _age.accept(pt.age(generation)); 132 } 133 134 // Calculate duration statistics 135 private void accept(final EvolutionDurations durations) { 136 final double selection = 137 toSeconds(durations.offspringSelectionDuration()) + 138 toSeconds(durations.survivorsSelectionDuration()); 139 final double alter = 140 toSeconds(durations.offspringAlterDuration()) + 141 toSeconds(durations.offspringFilterDuration()); 142 143 _selectionDuration.accept(selection); 144 _alterDuration.accept(alter); 145 _evaluationDuration 146 .accept(toSeconds(durations.evaluationDuration())); 147 _evolveDuration 148 .accept(toSeconds(durations.evolveDuration())); 149 } 150 151 private static double toSeconds(final Duration duration) { 152 return duration.toNanos()/1_000_000_000.0; 153 } 154 155 /* ************************************************************************* 156 * Evaluation timing statistics 157 * ************************************************************************/ 158 159 /** 160 * Return the duration statistics needed for selecting the population, in 161 * seconds. 162 * 163 * @return the duration statistics needed for selecting the population 164 */ 165 public DoubleMomentStatistics selectionDuration() { 166 return _selectionDuration; 167 } 168 169 /** 170 * Return the duration statistics needed for altering the population, in 171 * seconds. 172 * 173 * @return the duration statistics needed for altering the population 174 */ 175 public DoubleMomentStatistics alterDuration() { 176 return _alterDuration; 177 } 178 179 /** 180 * Return the duration statistics needed for evaluating the fitness function 181 * of the new individuals, in seconds. 182 * 183 * @return the duration statistics needed for evaluating the fitness 184 * function of the new individuals 185 */ 186 public DoubleMomentStatistics evaluationDuration() { 187 return _evaluationDuration; 188 } 189 190 /** 191 * Return the duration statistics needed for the whole evolved step, in 192 * seconds. 193 * 194 * @return the duration statistics needed for the whole evolve step 195 */ 196 public DoubleMomentStatistics evolveDuration() { 197 return _evolveDuration; 198 } 199 200 201 /* ************************************************************************* 202 * Evolution statistics 203 * ************************************************************************/ 204 205 /** 206 * Return the statistics about the killed individuals during the evolution 207 * process. 208 * 209 * @return killed individual statistics 210 */ 211 public IntMomentStatistics killed() { 212 return _killed; 213 } 214 215 /** 216 * Return the statistics about the invalid individuals during the evolution 217 * process. 218 * 219 * @return invalid individual statistics 220 */ 221 public IntMomentStatistics invalids() { 222 return _invalids; 223 } 224 225 /** 226 * Return the statistics about the altered individuals during the evolution 227 * process. 228 * 229 * @return altered individual statistics 230 */ 231 public IntMomentStatistics altered() { 232 return _altered; 233 } 234 235 /** 236 * Return the statistics about the individual's age. 237 * 238 * @return individual age statistics 239 */ 240 public LongMomentStatistics phenotypeAge() { 241 return _age; 242 } 243 244 /** 245 * Return the minimal and maximal fitness. 246 * 247 * @return minimal and maximal fitness 248 */ 249 public FitnessStatistics fitness() { 250 return _fitness; 251 } 252 253 final String cpattern = "| %22s %-51s|\n"; 254 final String spattern = "| %27s %-46s|\n"; 255 256 @Override 257 public String toString() { 258 return 259 "+---------------------------------------------------------------------------+\n" + 260 "| Time statistics |\n" + 261 "+---------------------------------------------------------------------------+\n" + 262 format(cpattern, "Selection:", d(_selectionDuration)) + 263 format(cpattern, "Altering:", d(_alterDuration)) + 264 format(cpattern, "Fitness calculation:", d(_evaluationDuration)) + 265 format(cpattern, "Overall execution:", d(_evolveDuration)) + 266 "+---------------------------------------------------------------------------+\n" + 267 "| Evolution statistics |\n" + 268 "+---------------------------------------------------------------------------+\n" + 269 format(cpattern, "Generations:", i(_altered.count())) + 270 format(cpattern, "Altered:", i(_altered)) + 271 format(cpattern, "Killed:", i(_killed)) + 272 format(cpattern, "Invalids:", i(_invalids)); 273 } 274 275 private static String d(final DoubleMomentStatistics statistics) { 276 return format( 277 "sum=%3.12f s; mean=%3.12f s", 278 statistics.sum(), statistics.mean() 279 ); 280 } 281 282 private static String i(final IntMomentStatistics statistics) { 283 final NumberFormat nf = NumberFormat.getIntegerInstance(); 284 return format( 285 "sum=%s; mean=%6.9f", 286 nf.format(statistics.sum()), statistics.mean() 287 ); 288 } 289 290 private static String i(final long value) { 291 final NumberFormat nf = NumberFormat.getIntegerInstance(); 292 return nf.format(value); 293 } 294 295 private static String p(final IntMomentStatistics statistics) { 296 final NumberFormat nf = NumberFormat.getIntegerInstance(); 297 return format( 298 "max=%s; mean=%6.6f; var=%6.6f", 299 nf.format(statistics.max()), 300 statistics.mean(), 301 statistics.variance() 302 ); 303 } 304 305 private static String p(final LongMomentStatistics statistics) { 306 final NumberFormat nf = NumberFormat.getIntegerInstance(); 307 return format( 308 "max=%s; mean=%6.6f; var=%6.6f", 309 nf.format(statistics.max()), 310 statistics.mean(), 311 statistics.variance() 312 ); 313 } 314 315 private static final class Comp< 316 C extends Comparable<? super C> 317 > 318 extends EvolutionStatistics<C, MinMax<C>> 319 { 320 private Comp() { 321 _fitness = MinMax.of(); 322 } 323 324 @Override 325 public void accept(final EvolutionResult<?, C> result) { 326 if (_fitness.max() == null) { 327 _fitness = MinMax.of(result.optimize().ascending()); 328 } 329 330 super.accept(result); 331 } 332 333 @Override 334 void accept(final Phenotype<?, C> pt, final long generation) { 335 super.accept(pt, generation); 336 _fitness.accept(pt.fitness()); 337 } 338 339 @Override 340 public String toString() { 341 return super.toString() + 342 "+---------------------------------------------------------------------------+\n" + 343 "| Population statistics |\n" + 344 "+---------------------------------------------------------------------------+\n" + 345 format(cpattern, "Age:", p(_age)) + 346 format(cpattern, "Fitness", "") + 347 format(spattern, "min =", _fitness.min()) + 348 format(spattern, "max =", _fitness.max()) + 349 "+---------------------------------------------------------------------------+"; 350 } 351 } 352 353 private static final class Num<N extends Number & Comparable<? super N>> 354 extends EvolutionStatistics<N, DoubleMomentStatistics> 355 { 356 private Num() { 357 _fitness = new DoubleMomentStatistics(); 358 } 359 360 @Override 361 void accept(final Phenotype<?, N> pt, final long generation) { 362 super.accept(pt, generation); 363 _fitness.accept(pt.fitness().doubleValue()); 364 } 365 366 @Override 367 public String toString() { 368 return super.toString() + 369 "+---------------------------------------------------------------------------+\n" + 370 "| Population statistics |\n" + 371 "+---------------------------------------------------------------------------+\n" + 372 format(cpattern, "Age:", p(_age)) + 373 format(cpattern, "Fitness:", "") + 374 format(spattern, "min =", d(_fitness.min())) + 375 format(spattern, "max =", d(_fitness.max())) + 376 format(spattern, "mean =", d(_fitness.mean())) + 377 format(spattern, "var =", d(_fitness.variance())) + 378 format(spattern, "std =", d(sqrt(_fitness.variance()))) + 379 "+---------------------------------------------------------------------------+"; 380 } 381 382 private static String d(final double value) { 383 return format("%3.12f", value); 384 } 385 } 386 387 public static <C extends Comparable<? super C>> 388 EvolutionStatistics<C, MinMax<C>> ofComparable() { 389 return new Comp<>(); 390 } 391 392 public static <N extends Number & Comparable<? super N>> 393 EvolutionStatistics<N, DoubleMomentStatistics> ofNumber() { 394 return new Num<>(); 395 } 396 397}