EvolutionParams.java
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  */
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.Serial;
036 import java.io.Serializable;
037 import java.util.Objects;
038 import java.util.stream.Stream;
039 
040 import io.jenetics.Alterer;
041 import io.jenetics.Gene;
042 import io.jenetics.Mutator;
043 import io.jenetics.Selector;
044 import io.jenetics.SinglePointCrossover;
045 import io.jenetics.TournamentSelector;
046 import 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  */
063 public final class EvolutionParams<
064     extends Gene<?, G>,
065     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         extends Gene<?, G>,
215         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 outthrows 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 }