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}