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