001/*
002 * Java Genetic Algorithm Library (jenetics-6.1.0).
003 * Copyright (c) 2007-2020 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 */
020package io.jenetics.engine;
021
022import static java.lang.String.format;
023import static java.util.Objects.requireNonNull;
024import static io.jenetics.internal.util.Requires.probability;
025import static io.jenetics.internal.util.SerialIO.readInt;
026import static io.jenetics.internal.util.SerialIO.readLong;
027import static io.jenetics.internal.util.SerialIO.writeInt;
028import static io.jenetics.internal.util.SerialIO.writeLong;
029
030import java.io.IOException;
031import java.io.InvalidObjectException;
032import java.io.ObjectInput;
033import java.io.ObjectInputStream;
034import java.io.ObjectOutput;
035import java.io.Serializable;
036import java.util.Objects;
037import java.util.stream.Stream;
038
039import io.jenetics.Alterer;
040import io.jenetics.Gene;
041import io.jenetics.Mutator;
042import io.jenetics.Selector;
043import io.jenetics.SinglePointCrossover;
044import io.jenetics.TournamentSelector;
045import 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 */
062public 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}