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