001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.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(final Selector<G, C> selector) {
250                        _offspringSelector = requireNonNull(selector);
251                        return this;
252                }
253
254                /**
255                 * The selector used for selecting the survivor population. <i>Default
256                 * values is set to {@code TournamentSelector<>(3)}.</i>
257                 *
258                 * @param selector used for selecting survivor population
259                 * @return {@code this} builder, for command chaining
260                 */
261                public Builder<G, C> survivorsSelector(final Selector<G, C> selector) {
262                        _survivorsSelector = requireNonNull(selector);
263                        return this;
264                }
265
266                /**
267                 * The selector used for selecting the survivors and offspring
268                 * population. <i>Default values is set to
269                 * {@code TournamentSelector<>(3)}.</i>
270                 *
271                 * @param selector used for selecting survivors and offspring population
272                 * @return {@code this} builder, for command chaining
273                 */
274                public Builder<G, C> selector(final Selector<G, C> selector) {
275                        _offspringSelector = requireNonNull(selector);
276                        _survivorsSelector = requireNonNull(selector);
277                        return this;
278                }
279
280                /**
281                 * The alterers used for alter the offspring population. <i>Default
282                 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
283                 * {@code new Mutator<>(0.15)}.</i>
284                 *
285                 * @param first the first alterer used for alter the offspring
286                 *        population
287                 * @param rest the rest of the alterers used for alter the offspring
288                 *        population
289                 * @return {@code this} builder, for command chaining
290                 * @throws java.lang.NullPointerException if one of the alterers is
291                 *         {@code null}.
292                 */
293                @SafeVarargs
294                public final Builder<G, C> alterers(
295                        final Alterer<G, C> first,
296                        final Alterer<G, C>... rest
297                ) {
298                        requireNonNull(first);
299                        Stream.of(rest).forEach(Objects::requireNonNull);
300
301                        _alterer = rest.length == 0
302                                ? first
303                                : Alterer.of(rest).compose(first);
304
305                        return this;
306                }
307
308                /**
309                 * The number of individuals which form the population. <i>Default
310                 * values is set to {@code 50}.</i>
311                 *
312                 * @param size the number of individuals of a population
313                 * @return {@code this} builder, for command chaining
314                 * @throws IllegalArgumentException if {@code size < 1}
315                 */
316                public Builder<G, C> populationSize(final int size) {
317                        if (size < 1) {
318                                throw new IllegalArgumentException(format(
319                                        "Population size must be greater than zero, but was %s.",
320                                        size
321                                ));
322                        }
323
324                        _populationSize = size;
325                        return this;
326                }
327
328
329                /**
330                 * The offspring fraction.
331                 *
332                 * @param fraction the offspring fraction
333                 * @return {@code this} builder, for command chaining
334                 * @throws IllegalArgumentException if the fraction is not within the
335                 *         range [0, 1].
336                 */
337                public Builder<G, C> offspringFraction(final double fraction) {
338                        _offspringFraction = probability(fraction);
339                        return this;
340                }
341
342                /**
343                 * The maximal allowed age of a phenotype. <i>Default values is set to
344                 * {@code 70}.</i>
345                 *
346                 * @param age the maximal phenotype age
347                 * @return {@code this} builder, for command chaining
348                 * @throws IllegalArgumentException if {@code age < 1}
349                 */
350                public Builder<G, C> maximalPhenotypeAge(final long age) {
351                        if (age < 1) {
352                                throw new IllegalArgumentException(format(
353                                        "Phenotype age must be greater than one, but was %s.", age
354                                ));
355                        }
356                        _maximalPhenotypeAge = age;
357                        return this;
358                }
359
360                /**
361                 * Builds a new {@code EvolutionParams} instance from the set properties.
362                 *
363                 * @return a new {@code EvolutionParams} instance from the set properties
364                 */
365                public EvolutionParams<G, C> build() {
366                        return new EvolutionParams<>(
367                                _survivorsSelector,
368                                _offspringSelector,
369                                _alterer,
370                                _populationSize,
371                                _offspringFraction,
372                                _maximalPhenotypeAge
373                        );
374                }
375
376
377                /* *********************************************************************
378                 * Current properties
379                 ***********************************************************************/
380
381                /**
382                 * Return the used {@link Alterer} of the GA.
383                 *
384                 * @return the used {@link Alterer} of the GA.
385                 */
386                public Alterer<G, C> alterer() {
387                        return _alterer;
388                }
389
390
391                /**
392                 * Return the maximal allowed phenotype age.
393                 *
394                 * @return the maximal allowed phenotype age
395                 */
396                public long maximalPhenotypeAge() {
397                        return _maximalPhenotypeAge;
398                }
399
400                /**
401                 * Return the used offspring {@link Selector} of the GA.
402                 *
403                 * @return the used offspring {@link Selector} of the GA.
404                 */
405                public Selector<G, C> offspringSelector() {
406                        return _offspringSelector;
407                }
408
409                /**
410                 * Return the used survivor {@link Selector} of the GA.
411                 *
412                 * @return the used survivor {@link Selector} of the GA.
413                 */
414                public Selector<G, C> survivorsSelector() {
415                        return _survivorsSelector;
416                }
417
418                /**
419                 * Return the number of individuals of a population.
420                 *
421                 * @return the number of individuals of a population
422                 */
423                public int populationSize() {
424                        return _populationSize;
425                }
426
427                /**
428                 * Return the offspring fraction.
429                 *
430                 * @return the offspring fraction.
431                 */
432                public double offspringFraction() {
433                        return _offspringFraction;
434                }
435
436                /* *************************************************************************
437                 * Derived properties.
438                 **************************************************************************/
439
440                /**
441                 * Return the number of offspring. <em>This is a derived property.</em>
442                 *
443                 * @return the offspring count.
444                 */
445                public int offspringSize() {
446                        return (int)Math.round(_populationSize*_offspringFraction);
447                }
448
449                /**
450                 * Return the number of survivors. <em>This is a derived property.</em>
451                 *
452                 * @return the number of survivors
453                 */
454                public int survivorsSize() {
455                        return _populationSize - offspringSize();
456                }
457
458        }
459
460        /* *************************************************************************
461         *  Java object serialization
462         * ************************************************************************/
463
464        @Serial
465        private Object writeReplace() {
466                return new SerialProxy(SerialProxy.EVOLUTION_PARAMS, this);
467        }
468
469        @Serial
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}