001 /*
002 * Java Genetic Algorithm Library (jenetics-6.3.0).
003 * Copyright (c) 2007-2021 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 6.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.durations());
122
123 _killed.accept(result.killCount());
124 _invalids.accept(result.invalidCount());
125 _altered.accept(result.alterCount());
126
127 result.population()
128 .forEach(pt -> accept(pt, result.generation()));
129 }
130
131 void accept(final Phenotype<?, C> pt, final long generation) {
132 _age.accept(pt.age(generation));
133 }
134
135 // Calculate duration statistics
136 private void accept(final EvolutionDurations durations) {
137 final double selection =
138 toSeconds(durations.offspringSelectionDuration()) +
139 toSeconds(durations.survivorsSelectionDuration());
140 final double alter =
141 toSeconds(durations.offspringAlterDuration()) +
142 toSeconds(durations.offspringFilterDuration());
143
144 _selectionDuration.accept(selection);
145 _alterDuration.accept(alter);
146 _evaluationDuration
147 .accept(toSeconds(durations.evaluationDuration()));
148 _evolveDuration
149 .accept(toSeconds(durations.evolveDuration()));
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 selectionDuration() {
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 alterDuration() {
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 evaluationDuration() {
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 evolveDuration() {
198 return _evolveDuration;
199 }
200
201
202 /* *************************************************************************
203 * Evolution statistics
204 * ************************************************************************/
205
206 /**
207 * Return the statistics about the killed individuals during the evolution
208 * process.
209 *
210 * @return killed individual statistics
211 */
212 public IntMomentStatistics killed() {
213 return _killed;
214 }
215
216 /**
217 * Return the statistics about the invalid individuals during the evolution
218 * process.
219 *
220 * @return invalid individual statistics
221 */
222 public IntMomentStatistics invalids() {
223 return _invalids;
224 }
225
226 /**
227 * Return the statistics about the altered individuals during the evolution
228 * process.
229 *
230 * @return altered individual statistics
231 */
232 public IntMomentStatistics altered() {
233 return _altered;
234 }
235
236 /**
237 * Return the statistics about the individuals age.
238 *
239 * @return individual age statistics
240 */
241 public LongMomentStatistics phenotypeAge() {
242 return _age;
243 }
244
245 /**
246 * Return the minimal and maximal fitness.
247 *
248 * @return minimal and maximal fitness
249 */
250 public FitnessStatistics fitness() {
251 return _fitness;
252 }
253
254 final String cpattern = "| %22s %-51s|\n";
255 final String spattern = "| %27s %-46s|\n";
256
257 @Override
258 public String toString() {
259 return
260 "+---------------------------------------------------------------------------+\n" +
261 "| Time statistics |\n" +
262 "+---------------------------------------------------------------------------+\n" +
263 format(cpattern, "Selection:", d(_selectionDuration)) +
264 format(cpattern, "Altering:", d(_alterDuration)) +
265 format(cpattern, "Fitness calculation:", d(_evaluationDuration)) +
266 format(cpattern, "Overall execution:", d(_evolveDuration)) +
267 "+---------------------------------------------------------------------------+\n" +
268 "| Evolution statistics |\n" +
269 "+---------------------------------------------------------------------------+\n" +
270 format(cpattern, "Generations:", i(_altered.count())) +
271 format(cpattern, "Altered:", i(_altered)) +
272 format(cpattern, "Killed:", i(_killed)) +
273 format(cpattern, "Invalids:", i(_invalids));
274 }
275
276 private static String d(final DoubleMomentStatistics statistics) {
277 return format(
278 "sum=%3.12f s; mean=%3.12f s",
279 statistics.sum(), statistics.mean()
280 );
281 }
282
283 private static String i(final IntMomentStatistics statistics) {
284 final NumberFormat nf = NumberFormat.getIntegerInstance();
285 return format(
286 "sum=%s; mean=%6.9f",
287 nf.format(statistics.sum()), statistics.mean()
288 );
289 }
290
291 private static String i(final long value) {
292 final NumberFormat nf = NumberFormat.getIntegerInstance();
293 return nf.format(value);
294 }
295
296 private static String p(final IntMomentStatistics statistics) {
297 final NumberFormat nf = NumberFormat.getIntegerInstance();
298 return format(
299 "max=%s; mean=%6.6f; var=%6.6f",
300 nf.format(statistics.max()),
301 statistics.mean(),
302 statistics.variance()
303 );
304 }
305
306 private static String p(final LongMomentStatistics statistics) {
307 final NumberFormat nf = NumberFormat.getIntegerInstance();
308 return format(
309 "max=%s; mean=%6.6f; var=%6.6f",
310 nf.format(statistics.max()),
311 statistics.mean(),
312 statistics.variance()
313 );
314 }
315
316 private static final class Comp<
317 C extends Comparable<? super C>
318 >
319 extends EvolutionStatistics<C, MinMax<C>>
320 {
321 private Comp() {
322 _fitness = MinMax.of();
323 }
324
325 @Override
326 public void accept(final EvolutionResult<?, C> result) {
327 if (_fitness.max() == null) {
328 _fitness = MinMax.of(result.optimize().ascending());
329 }
330
331 super.accept(result);
332 }
333
334 @Override
335 void accept(final Phenotype<?, C> pt, final long generation) {
336 super.accept(pt, generation);
337 _fitness.accept(pt.fitness());
338 }
339
340 @Override
341 public String toString() {
342 return super.toString() +
343 "+---------------------------------------------------------------------------+\n" +
344 "| Population statistics |\n" +
345 "+---------------------------------------------------------------------------+\n" +
346 format(cpattern, "Age:", p(_age)) +
347 format(cpattern, "Fitness", "") +
348 format(spattern, "min =", _fitness.min()) +
349 format(spattern, "max =", _fitness.max()) +
350 "+---------------------------------------------------------------------------+";
351 }
352 }
353
354 private static final class Num<N extends Number & Comparable<? super N>>
355 extends EvolutionStatistics<N, DoubleMomentStatistics>
356 {
357 private Num() {
358 _fitness = new DoubleMomentStatistics();
359 }
360
361 @Override
362 void accept(final Phenotype<?, N> pt, final long generation) {
363 super.accept(pt, generation);
364 _fitness.accept(pt.fitness().doubleValue());
365 }
366
367 @Override
368 public String toString() {
369 return super.toString() +
370 "+---------------------------------------------------------------------------+\n" +
371 "| Population statistics |\n" +
372 "+---------------------------------------------------------------------------+\n" +
373 format(cpattern, "Age:", p(_age)) +
374 format(cpattern, "Fitness:", "") +
375 format(spattern, "min =", d(_fitness.min())) +
376 format(spattern, "max =", d(_fitness.max())) +
377 format(spattern, "mean =", d(_fitness.mean())) +
378 format(spattern, "var =", d(_fitness.variance())) +
379 format(spattern, "std =", d(sqrt(_fitness.variance()))) +
380 "+---------------------------------------------------------------------------+";
381 }
382
383 private static String d(final double value) {
384 return format("%3.12f", value);
385 }
386 }
387
388 public static <C extends Comparable<? super C>>
389 EvolutionStatistics<C, MinMax<C>> ofComparable() {
390 return new Comp<>();
391 }
392
393 public static <N extends Number & Comparable<? super N>>
394 EvolutionStatistics<N, DoubleMomentStatistics> ofNumber() {
395 return new Num<>();
396 }
397
398 }
|