Statistics.java
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  */
020 package org.jenetics;
021 
022 import static java.lang.Double.NaN;
023 import static java.lang.String.format;
024 import static java.util.Objects.requireNonNull;
025 import static org.jenetics.internal.util.object.eq;
026 
027 import java.io.Serializable;
028 import java.util.concurrent.Executor;
029 
030 import org.jenetics.internal.util.HashBuilder;
031 
032 import org.jenetics.stat.Variance;
033 import org.jenetics.util.Duration;
034 import org.jenetics.util.FinalReference;
035 import org.jenetics.util.accumulators;
036 import 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 &mdash; <em>$Date: 2014-04-05 $</em>
044  */
045 public 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 &mdash; <em>$Date: 2014-04-05 $</em>
055      */
056     public static class Builder<
057         extends Gene<?, G>,
058         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 &mdash; <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 &mdash; <em>$Date: 2014-04-05 $</em>
555      */
556     public static class Calculator<
557         extends Gene<?, G>,
558         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 }