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.String.format;
023 import static java.util.Objects.requireNonNull;
024 import static io.jenetics.internal.util.Requires.probability;
025 import static io.jenetics.internal.util.SerialIO.readInt;
026 import static io.jenetics.internal.util.SerialIO.readLong;
027 import static io.jenetics.internal.util.SerialIO.writeInt;
028 import static io.jenetics.internal.util.SerialIO.writeLong;
029
030 import java.io.IOException;
031 import java.io.InvalidObjectException;
032 import java.io.ObjectInput;
033 import java.io.ObjectInputStream;
034 import java.io.ObjectOutput;
035 import java.io.Serializable;
036 import java.util.Objects;
037 import java.util.stream.Stream;
038
039 import io.jenetics.Alterer;
040 import io.jenetics.Gene;
041 import io.jenetics.Mutator;
042 import io.jenetics.Selector;
043 import io.jenetics.SinglePointCrossover;
044 import io.jenetics.TournamentSelector;
045 import io.jenetics.internal.util.Requires;
046
047 /**
048 * This class collects the parameters which control the behaviour of the
049 * evolution process. This doesn't include the parameters for the
050 * <em>technical</em> execution like the used execution service.
051 *
052 * @see Engine
053 * @see Engine.Builder
054 *
055 * @param <G> the gene type
056 * @param <C> the fitness function result type
057 *
058 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
059 * @version 5.2
060 * @since 5.2
061 */
062 public final class EvolutionParams<
063 G extends Gene<?, G>,
064 C extends Comparable<? super C>
065 >
066 implements Serializable
067 {
068
069 private static final long serialVersionUID = 1L;
070
071 private final Selector<G, C> _survivorsSelector;
072 private final Selector<G, C> _offspringSelector;
073 private final Alterer<G, C> _alterer;
074 private final int _populationSize;
075 private final double _offspringFraction;
076 private final long _maximalPhenotypeAge;
077
078 private EvolutionParams(
079 final Selector<G, C> survivorsSelector,
080 final Selector<G, C> offspringSelector,
081 final Alterer<G, C> alterer,
082 final int populationSize,
083 final double offspringFraction,
084 final long maximalPhenotypeAge
085 ) {
086 _survivorsSelector = requireNonNull(survivorsSelector);
087 _offspringSelector = requireNonNull(offspringSelector);
088 _alterer = requireNonNull(alterer);
089 _populationSize = Requires.positive(populationSize);
090 _offspringFraction = Requires.probability(offspringFraction);
091 _maximalPhenotypeAge = Requires.positive(maximalPhenotypeAge);
092 }
093
094
095 /**
096 * Return the used survivor {@link Selector} of the GA.
097 *
098 * @return the used survivor {@link Selector} of the GA.
099 */
100 public Selector<G, C> survivorsSelector() {
101 return _survivorsSelector;
102 }
103
104 /**
105 * Return the used offspring {@link Selector} of the GA.
106 *
107 * @return the used offspring {@link Selector} of the GA.
108 */
109 public Selector<G, C> offspringSelector() {
110 return _offspringSelector;
111 }
112
113 /**
114 * Return the used {@link Alterer} of the GA.
115 *
116 * @return the used {@link Alterer} of the GA.
117 */
118 public Alterer<G, C> alterer() {
119 return _alterer;
120 }
121
122
123 /**
124 * Return the population size.
125 *
126 * @return the population size
127 */
128 public int populationSize() {
129 return _populationSize;
130 }
131
132 /**
133 * Return the offspring fraction.
134 *
135 * @return the offspring fraction.
136 */
137 public double offspringFraction() {
138 return _offspringFraction;
139 }
140
141 /**
142 * Return the maximal allowed phenotype age.
143 *
144 * @return the maximal allowed phenotype age
145 */
146 public long maximalPhenotypeAge() {
147 return _maximalPhenotypeAge;
148 }
149
150
151 /* *************************************************************************
152 * Derived properties.
153 **************************************************************************/
154
155 /**
156 * Return the number of offspring. <em>This is a derived property.</em>
157 *
158 * @return the offspring count.
159 */
160 public int offspringSize() {
161 return (int)Math.rint(_populationSize*_offspringFraction);
162 }
163
164 /**
165 * Return the number of survivors. <em>This is a derived property.</em>
166 *
167 * @return the number of survivors
168 */
169 public int survivorsSize() {
170 return _populationSize - offspringSize();
171 }
172
173 /**
174 * Return a new builder object, initialized with {@code this} parameters.
175 *
176 * @return a new pre-filled builder object
177 */
178 public EvolutionParams.Builder<G, C> toBuilder() {
179 return EvolutionParams.<G, C>builder()
180 .survivorsSelector(survivorsSelector())
181 .offspringSelector(offspringSelector())
182 .alterers(alterer())
183 .populationSize(populationSize())
184 .offspringFraction(offspringFraction())
185 .maximalPhenotypeAge(maximalPhenotypeAge());
186 }
187
188 /**
189 * Create a new evolution parameter builder.
190 *
191 * @param <G> the gene type
192 * @param <C> the fitness function result type
193 * @return a new parameter builder
194 */
195 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
196 Builder<G, C> builder() {
197 return new Builder<>();
198 }
199
200
201 /* *************************************************************************
202 * Params builder
203 **************************************************************************/
204
205 /**
206 * Builder class for the evolution parameter.
207 *
208 * @param <G> the gene type
209 * @param <C> the fitness function result type
210 */
211 public static final class Builder<
212 G extends Gene<?, G>,
213 C extends Comparable<? super C>
214 > {
215
216 private Selector<G, C> _survivorsSelector = new TournamentSelector<>(3);
217 private Selector<G, C> _offspringSelector = new TournamentSelector<>(3);
218 private Alterer<G, C> _alterer = Alterer.of(
219 new SinglePointCrossover<G, C>(0.2),
220 new Mutator<>(0.15)
221 );
222 private int _populationSize = 50;
223 private double _offspringFraction = 0.6;
224 private long _maximalPhenotypeAge = 70;
225
226
227 private Builder() {
228 }
229
230 public Builder<G, C> evolutionParams(final EvolutionParams<G, C> params) {
231 survivorsSelector(params.survivorsSelector());
232 offspringSelector(params.offspringSelector());
233 alterers(params.alterer());
234 populationSize(params.populationSize());
235 offspringFraction(params.offspringFraction());
236 maximalPhenotypeAge(params.maximalPhenotypeAge());
237 return this;
238 }
239
240 /**
241 * The selector used for selecting the offspring population. <i>Default
242 * values is set to {@code TournamentSelector<>(3)}.</i>
243 *
244 * @param selector used for selecting the offspring population
245 * @return {@code this} builder, for command chaining
246 */
247 public Builder<G, C> offspringSelector(
248 final Selector<G, C> selector
249 ) {
250 _offspringSelector = requireNonNull(selector);
251 return this;
252 }
253
254 /**
255 * The selector used for selecting the survivors population. <i>Default
256 * values is set to {@code TournamentSelector<>(3)}.</i>
257 *
258 * @param selector used for selecting survivors population
259 * @return {@code this} builder, for command chaining
260 */
261 public Builder<G, C> survivorsSelector(
262 final Selector<G, C> selector
263 ) {
264 _survivorsSelector = requireNonNull(selector);
265 return this;
266 }
267
268 /**
269 * The selector used for selecting the survivors and offspring
270 * population. <i>Default values is set to
271 * {@code TournamentSelector<>(3)}.</i>
272 *
273 * @param selector used for selecting survivors and offspring population
274 * @return {@code this} builder, for command chaining
275 */
276 public Builder<G, C> selector(final Selector<G, C> selector) {
277 _offspringSelector = requireNonNull(selector);
278 _survivorsSelector = requireNonNull(selector);
279 return this;
280 }
281
282 /**
283 * The alterers used for alter the offspring population. <i>Default
284 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
285 * {@code new Mutator<>(0.15)}.</i>
286 *
287 * @param first the first alterer used for alter the offspring
288 * population
289 * @param rest the rest of the alterers used for alter the offspring
290 * population
291 * @return {@code this} builder, for command chaining
292 * @throws java.lang.NullPointerException if one of the alterers is
293 * {@code null}.
294 */
295 @SafeVarargs
296 public final Builder<G, C> alterers(
297 final Alterer<G, C> first,
298 final Alterer<G, C>... rest
299 ) {
300 requireNonNull(first);
301 Stream.of(rest).forEach(Objects::requireNonNull);
302
303 _alterer = rest.length == 0
304 ? first
305 : Alterer.of(rest).compose(first);
306
307 return this;
308 }
309
310 /**
311 * The number of individuals which form the population. <i>Default
312 * values is set to {@code 50}.</i>
313 *
314 * @param size the number of individuals of a population
315 * @return {@code this} builder, for command chaining
316 * @throws IllegalArgumentException if {@code size < 1}
317 */
318 public Builder<G, C> populationSize(final int size) {
319 if (size < 1) {
320 throw new IllegalArgumentException(format(
321 "Population size must be greater than zero, but was %s.",
322 size
323 ));
324 }
325
326 _populationSize = size;
327 return this;
328 }
329
330
331 /**
332 * The offspring fraction.
333 *
334 * @param fraction the offspring fraction
335 * @return {@code this} builder, for command chaining
336 * @throws IllegalArgumentException if the fraction is not within the
337 * range [0, 1].
338 */
339 public Builder<G, C> offspringFraction(final double fraction) {
340 _offspringFraction = probability(fraction);
341 return this;
342 }
343
344 /**
345 * The maximal allowed age of a phenotype. <i>Default values is set to
346 * {@code 70}.</i>
347 *
348 * @param age the maximal phenotype age
349 * @return {@code this} builder, for command chaining
350 * @throws IllegalArgumentException if {@code age < 1}
351 */
352 public Builder<G, C> maximalPhenotypeAge(final long age) {
353 if (age < 1) {
354 throw new IllegalArgumentException(format(
355 "Phenotype age must be greater than one, but was %s.", age
356 ));
357 }
358 _maximalPhenotypeAge = age;
359 return this;
360 }
361
362 /**
363 * Builds an new {@code EvolutionParams} instance from the set properties.
364 *
365 * @return an new {@code EvolutionParams} instance from the set properties
366 */
367 public EvolutionParams<G, C> build() {
368 return new EvolutionParams<>(
369 _survivorsSelector,
370 _offspringSelector,
371 _alterer,
372 _populationSize,
373 _offspringFraction,
374 _maximalPhenotypeAge
375 );
376 }
377
378
379 /* *********************************************************************
380 * Current properties
381 ***********************************************************************/
382
383 /**
384 * Return the used {@link Alterer} of the GA.
385 *
386 * @return the used {@link Alterer} of the GA.
387 */
388 public Alterer<G, C> alterer() {
389 return _alterer;
390 }
391
392
393 /**
394 * Return the maximal allowed phenotype age.
395 *
396 * @return the maximal allowed phenotype age
397 */
398 public long maximalPhenotypeAge() {
399 return _maximalPhenotypeAge;
400 }
401
402 /**
403 * Return the used offspring {@link Selector} of the GA.
404 *
405 * @return the used offspring {@link Selector} of the GA.
406 */
407 public Selector<G, C> offspringSelector() {
408 return _offspringSelector;
409 }
410
411 /**
412 * Return the used survivor {@link Selector} of the GA.
413 *
414 * @return the used survivor {@link Selector} of the GA.
415 */
416 public Selector<G, C> survivorsSelector() {
417 return _survivorsSelector;
418 }
419
420 /**
421 * Return the number of individuals of a population.
422 *
423 * @return the number of individuals of a population
424 */
425 public int populationSize() {
426 return _populationSize;
427 }
428
429 /**
430 * Return the offspring fraction.
431 *
432 * @return the offspring fraction.
433 */
434 public double offspringFraction() {
435 return _offspringFraction;
436 }
437
438 /* *************************************************************************
439 * Derived properties.
440 **************************************************************************/
441
442 /**
443 * Return the number of offspring. <em>This is a derived property.</em>
444 *
445 * @return the offspring count.
446 */
447 public int offspringSize() {
448 return (int)Math.round(_populationSize*_offspringFraction);
449 }
450
451 /**
452 * Return the number of survivors. <em>This is a derived property.</em>
453 *
454 * @return the number of survivors
455 */
456 public int survivorsSize() {
457 return _populationSize - offspringSize();
458 }
459
460 }
461
462 /* *************************************************************************
463 * Java object serialization
464 * ************************************************************************/
465
466 private Object writeReplace() {
467 return new Serial(Serial.EVOLUTION_PARAMS, this);
468 }
469
470 private void readObject(final ObjectInputStream stream)
471 throws InvalidObjectException
472 {
473 throw new InvalidObjectException("Serialization proxy required.");
474 }
475
476 void write(final ObjectOutput out) throws IOException {
477 out.writeObject(survivorsSelector());
478 out.writeObject(offspringSelector());
479 out.writeObject(alterer());
480 writeInt(populationSize(), out);
481 out.writeDouble(offspringFraction());
482 writeLong(maximalPhenotypeAge(), out);
483 }
484
485 @SuppressWarnings({"unchecked", "rawtypes"})
486 static EvolutionParams read(final ObjectInput in)
487 throws IOException, ClassNotFoundException
488 {
489 return new EvolutionParams(
490 (Selector)in.readObject(),
491 (Selector)in.readObject(),
492 (Alterer)in.readObject(),
493 readInt(in),
494 in.readDouble(),
495 readLong(in)
496 );
497 }
498
499 }
|