001/* 002 * Java Genetic Algorithm Library (jenetics-2.0.2). 003 * Copyright (c) 2007-2014 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 */ 020package org.jenetics; 021 022import static java.lang.Double.NaN; 023import static java.lang.String.format; 024import static java.util.Objects.requireNonNull; 025import static org.jenetics.internal.util.object.eq; 026 027import java.io.Serializable; 028import java.util.concurrent.Executor; 029 030import org.jenetics.internal.util.HashBuilder; 031 032import org.jenetics.stat.Variance; 033import org.jenetics.util.Duration; 034import org.jenetics.util.FinalReference; 035import org.jenetics.util.accumulators; 036import org.jenetics.util.accumulators.MinMax; 037 038/** 039 * Data object which holds performance indicators of a given {@link Population}. 040 * 041 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> 042 * @since 1.0 043 * @version 2.0 — <em>$Date: 2014-04-05 $</em> 044 */ 045public class Statistics<G extends Gene<?, G>, C extends Comparable<? super C>> 046 implements Serializable 047{ 048 049 /** 050 * Builder for the Statistics class. 051 * 052 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> 053 * @since 1.0 054 * @version 2.0 — <em>$Date: 2014-04-05 $</em> 055 */ 056 public static class Builder< 057 G extends Gene<?, G>, 058 C extends Comparable<? super C> 059 > 060 { 061 protected Optimize _optimize = Optimize.MAXIMUM; 062 protected int _generation = 0; 063 protected Phenotype<G, C> _best = null; 064 protected Phenotype<G, C> _worst = null; 065 protected int _samples = 0; 066 protected double _ageMean = NaN; 067 protected double _ageVariance = NaN; 068 protected int _killed = 0; 069 protected int _invalid = 0; 070 071 /** 072 * Create a new Statistics builder. 073 */ 074 public Builder() { 075 } 076 077 /** 078 * Set the values of this builder with the values of the given 079 * {@code statistics}. 080 * 081 * @param statistics the statistics values. If the {@code statistics} 082 * is {@code null} nothing is set. 083 * @return this builder instance. 084 */ 085 public Builder<G, C> statistics(final Statistics<G, C> statistics) { 086 if (statistics != null) { 087 _optimize = statistics._optimize; 088 _generation = statistics._generation; 089 _best = statistics._best; 090 _worst = statistics._worst; 091 _samples = statistics._samples; 092 _ageMean = statistics._ageMean; 093 _ageVariance = statistics._ageVariance; 094 _killed = statistics._killed; 095 _invalid = statistics._invalid; 096 } 097 return this; 098 } 099 100 public Builder<G, C> optimize(final Optimize optimize) { 101 _optimize = requireNonNull(optimize, "Optimize strategy"); 102 return this; 103 } 104 105 /** 106 * @see Statistics#getGeneration() 107 * 108 * @param generation the current GA generation 109 * @return this builder instance 110 */ 111 public Builder<G, C> generation(final int generation) { 112 _generation = generation; 113 return this; 114 } 115 116 /** 117 * @see Statistics#getBestPhenotype() 118 * 119 * @param best the best phenotype 120 * @return this builder instance 121 */ 122 public Builder<G, C> bestPhenotype(final Phenotype<G, C> best) { 123 _best = best; 124 return this; 125 } 126 127 /** 128 * @see Statistics#getWorstPhenotype() 129 * 130 * @param worst the worst phenotype 131 * @return this builder instance 132 */ 133 public Builder<G, C> worstPhenotype(final Phenotype<G, C> worst) { 134 _worst = worst; 135 return this; 136 } 137 138 /** 139 * @see Statistics#getSamples() 140 * 141 * @param samples the number of samples for the statistics object. 142 * @return this builder instance 143 */ 144 public Builder<G, C> samples(final int samples) { 145 _samples = samples; 146 return this; 147 } 148 149 /** 150 * @see Statistics#getAgeMean() 151 * 152 * @param ageMean the mean of the population age 153 * @return this builder instance 154 */ 155 public Builder<G, C> ageMean(final double ageMean) { 156 _ageMean = ageMean; 157 return this; 158 } 159 160 /** 161 * @see Statistics#getAgeVariance() 162 * 163 * @param ageVariance the variance of the population age 164 * @return this builder instance 165 */ 166 public Builder<G, C> ageVariance(final double ageVariance) { 167 _ageVariance = ageVariance; 168 return this; 169 } 170 171 /** 172 * @see Statistics#getInvalid() 173 * 174 * @param invalid the number of valid individuals 175 * @return this builder instance 176 */ 177 public Builder<G, C> invalid(final int invalid) { 178 _invalid = invalid; 179 return this; 180 } 181 182 /** 183 * @see Statistics#getKilled() 184 * 185 * @param killed the number of killed individuals 186 * @return this builder instance 187 */ 188 public Builder<G, C> killed(final int killed) { 189 _killed = killed; 190 return this; 191 } 192 193 /** 194 * Return a new Statistics object with the builder values. 195 * 196 * @return new Statistics object with the builder values. 197 */ 198 public Statistics<G, C> build() { 199 return new Statistics<>( 200 _optimize, 201 _generation, 202 _best, 203 _worst, 204 _samples, 205 _ageMean, 206 _ageVariance, 207 _killed, 208 _invalid 209 ); 210 } 211 } 212 213 private static final long serialVersionUID = 3L; 214 215 protected final Optimize _optimize; 216 protected final int _generation; 217 protected final Phenotype<G, C> _best; 218 protected final Phenotype<G, C> _worst; 219 protected final int _samples; 220 protected final double _ageMean; 221 protected final double _ageVariance; 222 protected final int _killed; 223 protected final int _invalid; 224 225 private final FinalReference<Time> _time = new FinalReference<>(new Time()); 226 227 228 /** 229 * Evaluates statistic values from a given population. The given phenotypes 230 * may be {@code null} 231 * 232 * @param optimize the optimization strategy used 233 * @param generation the generation for this statistics 234 * @param best best phenotype 235 * @param worst worst phenotype 236 * @param samples number of samples of this statistics 237 * @param ageMean the mean value of the individuals age 238 * @param ageVariance the variance value of the individuals ages 239 * @param killed the number of killed individuals 240 * @param invalid the number of invalid individuals 241 */ 242 protected Statistics( 243 final Optimize optimize, 244 final int generation, 245 final Phenotype<G, C> best, 246 final Phenotype<G, C> worst, 247 final int samples, 248 final double ageMean, 249 final double ageVariance, 250 final int killed, 251 final int invalid 252 ) { 253 _optimize = optimize; 254 _generation = generation; 255 _best = best; 256 _worst = worst; 257 _samples = samples; 258 _ageMean = ageMean; 259 _ageVariance = ageVariance; 260 _killed = killed; 261 _invalid = invalid; 262 } 263 264 /** 265 * Return the optimize strategy of the GA. 266 * 267 * @return the optimize strategy of the GA. 268 */ 269 public Optimize getOptimize() { 270 return _optimize; 271 } 272 273 /** 274 * Return the generation of this statistics. 275 * 276 * @return the generation of this statistics. 277 */ 278 public int getGeneration() { 279 return _generation; 280 } 281 282 /** 283 * Return the time statistic object which contains the durations of the 284 * different GA execution steps. 285 * 286 * @return the time statistic object. 287 */ 288 public Time getTime() { 289 return _time.get(); 290 } 291 292 /** 293 * Return the best population Phenotype. 294 * 295 * @return The best population Phenotype. 296 */ 297 public Phenotype<G, C> getBestPhenotype() { 298 return _best; 299 } 300 301 /** 302 * Return the worst population Phenotype. 303 * 304 * @return The worst population Phenotype. 305 */ 306 public Phenotype<G, C> getWorstPhenotype() { 307 return _worst; 308 } 309 310 /** 311 * Return the best population fitness. 312 * 313 * @return The best population fitness. 314 */ 315 public C getBestFitness() { 316 return _best != null ? _best.getFitness() : null; 317 } 318 319 /** 320 * Return the worst population fitness. 321 * 322 * @return The worst population fitness. 323 */ 324 public C getWorstFitness() { 325 return _worst != null ? _worst.getFitness() : null; 326 } 327 328 /** 329 * Return the number of samples this statistics has aggregated. 330 * 331 * @return the number of samples this statistics has aggregated. 332 */ 333 public int getSamples() { 334 return _samples; 335 } 336 337 /** 338 * Return the average (mean) age of the individuals of the aggregated 339 * population. 340 * 341 * @return the average population age. 342 */ 343 public double getAgeMean() { 344 return _ageMean; 345 } 346 347 /** 348 * Return the age variance of the individuals of the aggregated population. 349 * 350 * @return the age variance of the individuals of the aggregated population. 351 */ 352 public double getAgeVariance() { 353 return _ageVariance; 354 } 355 356 /** 357 * Return the number of invalid individuals. 358 * 359 * @return the number of invalid individuals. 360 */ 361 public int getInvalid() { 362 return _invalid; 363 } 364 365 /** 366 * Return the number of killed individuals. 367 * 368 * @return the number of killed individuals. 369 */ 370 public int getKilled() { 371 return _killed; 372 } 373 374 @Override 375 public int hashCode() { 376 return HashBuilder.of(getClass()). 377 and(_optimize). 378 and(_generation). 379 and(_ageMean). 380 and(_ageVariance). 381 and(_best). 382 and(_worst). 383 and(_invalid). 384 and(_samples). 385 and(_killed).value(); 386 } 387 388 @Override 389 public boolean equals(final Object obj) { 390 if (obj == this) { 391 return true; 392 } 393 if (obj == null || getClass() != obj.getClass()) { 394 return false; 395 } 396 397 final Statistics<?, ?> statistics = (Statistics<?, ?>)obj; 398 return eq(_optimize, statistics._optimize) && 399 eq(_generation, statistics._generation) && 400 eq(_ageMean, statistics._ageMean) && 401 eq(_ageVariance, statistics._ageVariance) && 402 eq(_best, statistics._best) && 403 eq(_worst, statistics._worst) && 404 eq(_invalid, statistics._invalid) && 405 eq(_samples, statistics._samples) && 406 eq(_killed, statistics._killed); 407 } 408 409 @Override 410 public String toString() { 411 final String spattern = "| %28s: %-26s|\n"; 412 final String fpattern = "| %28s: %-26.11f|\n"; 413 final String ipattern = "| %28s: %-26d|\n"; 414 415 final StringBuilder out = new StringBuilder(); 416 out.append("+---------------------------------------------------------+\n"); 417 out.append("| Population Statistics |\n"); 418 out.append("+---------------------------------------------------------+\n"); 419 out.append(format(fpattern, "Age mean", _ageMean)); 420 out.append(format(fpattern, "Age variance", _ageVariance)); 421 out.append(format(ipattern, "Samples", _samples)); 422 out.append(format(spattern, "Best fitness", getBestFitness())); 423 out.append(format(spattern, "Worst fitness", getWorstFitness())); 424 out.append("+---------------------------------------------------------+"); 425 426 return out.toString(); 427 } 428 429 /** 430 * Class which holds time statistic values. 431 * 432 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> 433 * @since 1.0 434 * @version 2.0 — <em>$Date: 2014-04-05 $</em> 435 */ 436 public static final class Time implements Serializable { 437 private static final long serialVersionUID = 2L; 438 439 private static final Duration ZERO = Duration.ofNanos(0); 440 441 /** 442 * Create a new time object with zero time values. The time references 443 * can only be set once. If you try to set the values twice an 444 * {@link IllegalStateException} is thrown. 445 */ 446 public Time() { 447 } 448 449 /** 450 * The overall execution time. 451 * The time can be set only once, otherwise an IllegalArgumentException 452 * is thrown. 453 */ 454 public final FinalReference<Duration> 455 execution = new FinalReference<>(ZERO); 456 457 /** 458 * The selection time. 459 * The time can be set only once, otherwise an IllegalArgumentException 460 * is thrown. 461 */ 462 public final FinalReference<Duration> 463 selection = new FinalReference<>(ZERO); 464 465 /** 466 * The alter time. 467 * The time can be set only once, otherwise an IllegalArgumentException 468 * is thrown. 469 */ 470 public final FinalReference<Duration> 471 alter = new FinalReference<>(ZERO); 472 473 /** 474 * Combination time between offspring and survivors. 475 * The time can be set only once, otherwise an IllegalArgumentException 476 * is thrown. 477 */ 478 public final FinalReference<Duration> 479 combine = new FinalReference<>(ZERO); 480 481 /** 482 * The evaluation time. 483 * The time can be set only once, otherwise an IllegalArgumentException 484 * is thrown. 485 */ 486 public final FinalReference<Duration> 487 evaluation = new FinalReference<>(ZERO); 488 489 /** 490 * The statistics time. 491 * The time can be set only once, otherwise an IllegalArgumentException 492 * is thrown. 493 */ 494 public final FinalReference<Duration> 495 statistics = new FinalReference<>(ZERO); 496 497 498 @Override 499 public int hashCode() { 500 return HashBuilder.of(getClass()). 501 and(alter). 502 and(combine). 503 and(evaluation). 504 and(execution). 505 and(selection). 506 and(statistics).value(); 507 } 508 509 @Override 510 public boolean equals(final Object object) { 511 if (object == this) { 512 return true; 513 } 514 if (object == null || object.getClass() != getClass()) { 515 return false; 516 } 517 518 final Statistics.Time time = (Statistics.Time)object; 519 return eq(alter.get(), time.alter.get()) && 520 eq(combine.get(), time.combine.get()) && 521 eq(evaluation.get(), time.evaluation.get()) && 522 eq(execution.get(), time.execution.get()) && 523 eq(selection.get(), time.selection.get()) && 524 eq(statistics.get(), time.statistics.get()); 525 } 526 527 @Override 528 public String toString() { 529 final String pattern = "| %28s: %-26.11f|\n"; 530 531 final StringBuilder out = new StringBuilder(); 532 out.append("+---------------------------------------------------------+\n"); 533 out.append("| Time Statistics |\n"); 534 out.append("+---------------------------------------------------------+\n"); 535 out.append(format(pattern, "Select time", selection.get().toSeconds())); 536 out.append(format(pattern, "Alter time", alter.get().toSeconds())); 537 out.append(format(pattern, "Combine time", combine.get().toSeconds())); 538 out.append(format(pattern, "Fitness calculation time", evaluation.get().toSeconds())); 539 out.append(format(pattern, "Statistics calculation time", statistics.get().toSeconds())); 540 out.append(format(pattern, "Overall execution time", execution.get().toSeconds())); 541 out.append("+---------------------------------------------------------+"); 542 543 return out.toString(); 544 } 545 } 546 547 548 /** 549 * Class for calculating the statistics. This class serves also as factory 550 * for the Statistics class. 551 * 552 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> 553 * @since 1.0 554 * @version 2.0 — <em>$Date: 2014-04-05 $</em> 555 */ 556 public static class Calculator< 557 G extends Gene<?, G>, 558 C extends Comparable<? super C> 559 > 560 { 561 562 /** 563 * Create a new calculator object. 564 */ 565 public Calculator() { 566 } 567 568 /** 569 * Create a new statistics object from the given {@code population} at 570 * the given {@code generation}. 571 * 572 * @param population the population to aggregate. 573 * @param generation the current GA generation. 574 * @param opt the optimization <i>direction</i>. 575 * @return a new statistics object generated from the given arguments. 576 */ 577 public Statistics.Builder<G, C> evaluate( 578 final Executor executor, 579 final Iterable<? extends Phenotype<G, C>> population, 580 final int generation, 581 final Optimize opt 582 ) { 583 final Builder<G, C> builder = new Builder<>(); 584 builder.generation(generation); 585 builder.optimize(opt); 586 587 final MinMax<Phenotype<G, C>> minMax = new MinMax<>(); 588 final Variance<Integer> age = new Variance<>(); 589 590 accumulators.<Phenotype<G, C>>accumulate( 591 executor, 592 population, 593 minMax, 594 age.map(Phenotype.Age(generation)) 595 ); 596 597 builder.bestPhenotype(opt.best(minMax.getMax(), minMax.getMin())); 598 builder.worstPhenotype(opt.worst(minMax.getMax(), minMax.getMin())); 599 builder.samples((int)minMax.getSamples()); 600 builder.ageMean(age.getMean()); 601 builder.ageVariance(age.getVariance()); 602 603 return builder; 604 } 605 606 } 607 608}