EvolutionStatistics.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.0.0).
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.engine;
021 
022 import static java.lang.String.format;
023 
024 import java.text.NumberFormat;
025 import java.time.Duration;
026 import java.util.function.Consumer;
027 
028 import org.jenetics.Phenotype;
029 import org.jenetics.stat.DoubleMomentStatistics;
030 import org.jenetics.stat.IntMomentStatistics;
031 import org.jenetics.stat.LongMomentStatistics;
032 import org.jenetics.stat.MinMax;
033 
034 /**
035  * This class can be used to gather additional statistic information of an
036  * evolution process. The additional information can be useful during the
037  * development phase of the GA or while testing the GA's performance. The
038  * following example shows how to integrate the <i>statistics</i> object into
039  * your evolution <i>stream</i>.
040  *
041  * [code]
042  * final Engine&lt;DoubleGene, Double&gt; engine = ...
043  * final EvolutionStatistics&lt;Double, DoubleMomentStatistics&gt; statistics =
044  *     EvolutionStatistics.ofNumber();
045  *
046  * final Phenotype&lt;DoubleGene, Double&gt; result = engine.stream()
047  *     .limit(bySteadyFitness(7))
048  *     .limit(100)
049  *     .peek(statistics)
050  *     .collect(toBestPhenotype());
051  *
052  * System.println(statistics);
053  * [/code]
054  *
055  <b>Example output</b>
056  *
057  * [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  +---------------------------------------------------------------------------+
082  * [/code]
083  *
084  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
085  @since 3.0
086  @version 3.0 &mdash; <em>$Date: 2014-12-28 $</em>
087  */
088 public abstract class EvolutionStatistics<
089     extends Comparable<? super C>,
090     FitnessStatistics
091     >
092     implements Consumer<EvolutionResult<?, C>>
093 {
094 
095     // The duration statistics values.
096     private final DoubleMomentStatistics
097         _selectionDuration = new DoubleMomentStatistics();
098     private final DoubleMomentStatistics
099         _alterDuration = new DoubleMomentStatistics();
100     private final DoubleMomentStatistics
101         _evaluationDuration = new DoubleMomentStatistics();
102     private final DoubleMomentStatistics
103         _evolveDuration = new DoubleMomentStatistics();
104 
105     // The evolution statistics values.
106     private final IntMomentStatistics _killed = new IntMomentStatistics();
107     private final IntMomentStatistics _invalids = new IntMomentStatistics();
108     private final IntMomentStatistics _altered = new IntMomentStatistics();
109 
110     // The population statistics values.
111     final LongMomentStatistics _age = new LongMomentStatistics();
112     FitnessStatistics _fitness = null;
113 
114     EvolutionStatistics() {
115     }
116 
117     @Override
118     public void accept(final EvolutionResult<?, C> result) {
119         accept(result.getDurations());
120 
121         _killed.accept(result.getKillCount());
122         _invalids.accept(result.getInvalidCount());
123         _altered.accept(result.getAlterCount());
124 
125         result.getPopulation()
126             .forEach(pt -> accept(pt, result.getGeneration()));
127     }
128 
129     void accept(final Phenotype<?, C> pt, final long generation) {
130         _age.accept(pt.getAge(generation));
131     }
132 
133     // Calculate duration statistics
134     private void accept(final EvolutionDurations durations) {
135         final double selection =
136             toSeconds(durations.getOffspringSelectionDuration()) +
137                 toSeconds(durations.getSurvivorsSelectionDuration());
138         final double alter =
139             toSeconds(durations.getOffspringAlterDuration()) +
140                 toSeconds(durations.getOffspringFilterDuration());
141 
142         _selectionDuration.accept(selection);
143         _alterDuration.accept(alter);
144         _evaluationDuration
145             .accept(toSeconds(durations.getEvaluationDuration()));
146         _evolveDuration
147             .accept(toSeconds(durations.getEvolveDuration()));
148     }
149 
150     private static double toSeconds(final Duration duration) {
151         return duration.toNanos()/1_000_000_000.0;
152     }
153 
154     /* *************************************************************************
155      * Evaluation timing statistics
156      * ************************************************************************/
157 
158     /**
159      * Return the duration statistics needed for selecting the population, in
160      * seconds.
161      *
162      @return the duration statistics needed for selecting the population
163      */
164     public DoubleMomentStatistics getSelectionDuration() {
165         return _selectionDuration;
166     }
167 
168     /**
169      * Return the duration statistics needed for altering the population, in
170      * seconds.
171      *
172      @return the duration statistics needed for altering the population
173      */
174     public DoubleMomentStatistics getAlterDuration() {
175         return _alterDuration;
176     }
177 
178     /**
179      * Return the duration statistics needed for evaluating the fitness function
180      * of the new individuals, in seconds.
181      *
182      @return the duration statistics needed for evaluating the fitness
183      *         function of the new individuals
184      */
185     public DoubleMomentStatistics getEvaluationDuration() {
186         return _evaluationDuration;
187     }
188 
189     /**
190      * Return the duration statistics needed for the whole evolve step, in
191      * seconds.
192      *
193      @return the duration statistics needed for the whole evolve step
194      */
195     public DoubleMomentStatistics getEvolveDuration() {
196         return _evolveDuration;
197     }
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 getKilled() {
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 getInvalids() {
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 getAltered() {
232         return _altered;
233     }
234 
235     /**
236      * Return the statistics about the individuals age.
237      *
238      @return individual age statistics
239      */
240     public LongMomentStatistics getPhenotypeAge() {
241         return _age;
242     }
243 
244     /**
245      * Return the minimal and maximal fitness.
246      *
247      @return minimal and maximal fitness
248      */
249     public FitnessStatistics getFitness() {
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.getCount())) +
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.getSum(), statistics.getMean()
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.getSum()), statistics.getMean()
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.getMax()),
300             statistics.getMean(),
301             statistics.getVariance()
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.getMax()),
310             statistics.getMean(),
311             statistics.getVariance()
312         );
313     }
314 
315     private static final class Comp<
316         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.getMax() == null) {
327                 _fitness = MinMax.of(result.getOptimize().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.getFitness());
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.getMin()) +
348                 format(spattern, "max =", _fitness.getMax()) +
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.getFitness().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.getMin())) +
375                 format(spattern, "max  =", d(_fitness.getMax())) +
376                 format(spattern, "mean =", d(_fitness.getMean())) +
377                 format(spattern, "var  =", d(_fitness.getVariance())) +
378                 "+---------------------------------------------------------------------------+";
379         }
380 
381         private static String d(final double value) {
382             return format("%3.12f", value);
383         }
384     }
385 
386     public static <C extends Comparable<? super C>>
387     EvolutionStatistics<C, MinMax<C>> ofComparable() {
388         return new Comp<>();
389     }
390 
391     public static <N extends Number & Comparable<? super N>>
392     EvolutionStatistics<N, DoubleMomentStatistics> ofNumber() {
393         return new Num<>();
394     }
395 
396 }