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 &mdash; <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 &mdash; <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 &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                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}