001 /*
002 * Java Genetic Algorithm Library (jenetics-3.0.0).
003 * Copyright (c) 2007-2014 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@gmx.at)
019 */
020 package org.jenetics.engine;
021
022 import static java.lang.Math.round;
023 import static java.lang.String.format;
024 import static java.util.Objects.requireNonNull;
025 import static org.jenetics.Population.toPopulation;
026 import static org.jenetics.internal.util.require.probability;
027
028 import java.time.Clock;
029 import java.util.Iterator;
030 import java.util.Objects;
031 import java.util.concurrent.CompletableFuture;
032 import java.util.concurrent.Executor;
033 import java.util.concurrent.ForkJoinPool;
034 import java.util.function.Function;
035 import java.util.stream.Stream;
036 import java.util.stream.StreamSupport;
037
038 import org.jenetics.internal.util.Concurrency;
039 import org.jenetics.internal.util.NanoClock;
040 import org.jenetics.internal.util.require;
041
042 import org.jenetics.Alterer;
043 import org.jenetics.Chromosome;
044 import org.jenetics.Gene;
045 import org.jenetics.Genotype;
046 import org.jenetics.Mutator;
047 import org.jenetics.Optimize;
048 import org.jenetics.Phenotype;
049 import org.jenetics.Population;
050 import org.jenetics.Selector;
051 import org.jenetics.SinglePointCrossover;
052 import org.jenetics.TournamentSelector;
053 import org.jenetics.util.Factory;
054
055 /**
056 * Genetic algorithm <em>engine</em> which is the main class. The following
057 * example shows the main steps in initializing and executing the GA.
058 *
059 * [code]
060 * public class RealFunction {
061 * // Definition of the fitness function.
062 * private static Double evaluate(final Genotype<DoubleGene> gt) {
063 * final double x = gt.getGene().doubleValue();
064 * return cos(0.5 + sin(x)) * cos(x);
065 * }
066 *
067 * public static void main(String[] args) {
068 * // Create/configuring the engine via its builder.
069 * final Engine<DoubleGene, Double> engine = Engine
070 * .builder(
071 * RealFunction::evaluate,
072 * DoubleChromosome.of(0.0, 2.0*PI))
073 * .populationSize(500)
074 * .optimize(Optimize.MINIMUM)
075 * .alterers(
076 * new Mutator<>(0.03),
077 * new MeanAlterer<>(0.6))
078 * .build();
079 *
080 * // Execute the GA (engine).
081 * final Phenotype<DoubleGene, Double> result = engine.stream()
082 * // Truncate the evolution stream if no better individual could
083 * // be found after 5 consecutive generations.
084 * .limit(bySteadyFitness(5))
085 * // Terminate the evolution after maximal 100 generations.
086 * .limit(100)
087 * .collect(toBestPhenotype());
088 * }
089 * }
090 * [/code]
091 *
092 * The architecture allows to decouple the configuration of the engine from the
093 * execution. The {@code Engine} is configured via the {@code Engine.Builder}
094 * class and can't be changed after creation. The actual <i>evolution</i> is
095 * performed by the {@link EvolutionStream}, which is created by the
096 * {@code Engine}.
097 * <p>
098 * <em>
099 * <b>This class is thread safe:</b>
100 * No mutable state is maintained by the engine. Therefore it is save to
101 * create multiple evolution streams with one engine, which may be actually
102 * used in different threads.
103 * </em>
104 *
105 * @see Engine.Builder
106 * @see EvolutionResult
107 * @see EvolutionStream
108 * @see EvolutionStatistics
109 *
110 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
111 * @since 3.0
112 * @version 3.0 — <em>$Date: 2014-12-28 $</em>
113 */
114 public final class Engine<
115 G extends Gene<?, G>,
116 C extends Comparable<? super C>
117 >
118 {
119
120 // Needed context for population evolving.
121 private final Function<? super Genotype<G>, ? extends C> _fitnessFunction;
122 private final Function<? super C, ? extends C> _fitnessScaler;
123 private final Factory<Genotype<G>> _genotypeFactory;
124 private final Selector<G, C> _survivorsSelector;
125 private final Selector<G, C> _offspringSelector;
126 private final Alterer<G, C> _alterer;
127 private final Optimize _optimize;
128 private final int _offspringCount;
129 private final int _survivorsCount;
130 private final long _maximalPhenotypeAge;
131
132 // Execution context for concurrent execution of evolving steps.
133 private final TimedExecutor _executor;
134 private final Clock _clock;
135
136
137 /**
138 * Create a new GA engine with the given parameters.
139 *
140 * @param genotypeFactory the genotype factory this GA is working with.
141 * @param fitnessFunction the fitness function this GA is using.
142 * @param fitnessScaler the fitness scaler this GA is using.
143 * @param survivorsSelector the selector used for selecting the survivors
144 * @param offspringSelector the selector used for selecting the offspring
145 * @param alterer the alterer used for altering the offspring
146 * @param optimize the kind of optimization (minimize or maximize)
147 * @param offspringCount the number of the offspring individuals
148 * @param survivorsCount the number of the survivor individuals
149 * @param maximalPhenotypeAge the maximal age of an individual
150 * @param executor the executor used for executing the single evolve steps
151 * @param clock the clock used for calculating the timing results
152 * @throws NullPointerException if one of the arguments is {@code null}
153 * @throws IllegalArgumentException if the given integer values are smaller
154 * than one.
155 */
156 Engine(
157 final Function<? super Genotype<G>, ? extends C> fitnessFunction,
158 final Function<? super C, ? extends C> fitnessScaler,
159 final Factory<Genotype<G>> genotypeFactory,
160 final Selector<G, C> survivorsSelector,
161 final Selector<G, C> offspringSelector,
162 final Alterer<G, C> alterer,
163 final Optimize optimize,
164 final int offspringCount,
165 final int survivorsCount,
166 final long maximalPhenotypeAge,
167 final Executor executor,
168 final Clock clock
169 ) {
170 _fitnessFunction = requireNonNull(fitnessFunction);
171 _fitnessScaler = requireNonNull(fitnessScaler);
172 _genotypeFactory = requireNonNull(genotypeFactory);
173 _survivorsSelector = requireNonNull(survivorsSelector);
174 _offspringSelector = requireNonNull(offspringSelector);
175 _alterer = requireNonNull(alterer);
176 _optimize = requireNonNull(optimize);
177
178 _offspringCount = require.positive(offspringCount);
179 _survivorsCount = require.positive(survivorsCount);
180 _maximalPhenotypeAge = require.positive(maximalPhenotypeAge);
181
182 _executor = new TimedExecutor(requireNonNull(executor));
183 _clock = requireNonNull(clock);
184 }
185
186 /**
187 * Perform one evolution step with the given {@code population} and
188 * {@code generation}. New phenotypes are created with the fitness function
189 * and fitness scaler defined by this <em>engine</em>.
190 * <p>
191 * <em>This method is thread-safe.</em>
192 *
193 * @param population the population to evolve
194 * @param generation the current generation; used for calculating the
195 * phenotype age.
196 * @return the evolution result
197 * @throws java.lang.NullPointerException if the given {@code population} is
198 * {@code null}
199 */
200 public EvolutionResult<G, C> evolve(
201 final Population<G, C> population,
202 final long generation
203 ) {
204 return evolve(new EvolutionStart<>(population, generation));
205 }
206
207 /**
208 * Performs one generation step.
209 *
210 * @param start the evolution start state
211 * @return the resulting evolution state
212 */
213 EvolutionResult<G, C> evolve(final EvolutionStart<G, C> start) {
214 final Timer timer = Timer.of().start();
215
216 // Select the offspring population.
217 final CompletableFuture<TimedResult<Population<G, C>>> offspring =
218 _executor.async(() ->
219 selectOffspring(start.population),
220 _clock
221 );
222
223 // Select the survivor population.
224 final CompletableFuture<TimedResult<Population<G, C>>> survivors =
225 _executor.async(() ->
226 selectSurvivors(start.population),
227 _clock
228 );
229
230 // Altering the offspring population.
231 final CompletableFuture<TimedResult<AlterResult<G, C>>> alteredOffspring =
232 _executor.thenApply(offspring, p ->
233 alter(p.result, start.generation),
234 _clock
235 );
236
237 // Filter and replace invalid and to old survivor individuals.
238 final CompletableFuture<TimedResult<FilterResult<G, C>>> filteredSurvivors =
239 _executor.thenApply(survivors, pop ->
240 filter(pop.result, start.generation),
241 _clock
242 );
243
244 // Filter and replace invalid and to old offspring individuals.
245 final CompletableFuture<TimedResult<FilterResult<G, C>>> filteredOffspring =
246 _executor.thenApply(alteredOffspring, pop ->
247 filter(pop.result.population, start.generation),
248 _clock
249 );
250
251 // Combining survivors and offspring to the new population.
252 final CompletableFuture<Population<G, C>> population =
253 filteredSurvivors.thenCombineAsync(filteredOffspring, (s, o) -> {
254 final Population<G, C> pop = s.result.population;
255 pop.addAll(o.result.population);
256 return pop;
257 },
258 _executor.get()
259 );
260
261 // Evaluate the fitness-function and wait for result.
262 final TimedResult<Population<G, C>> result = population
263 .thenApply(TimedResult.of(this::evaluate, _clock))
264 .join();
265
266 final EvolutionDurations durations = EvolutionDurations.of(
267 offspring.join().duration,
268 survivors.join().duration,
269 alteredOffspring.join().duration,
270 filteredOffspring.join().duration,
271 filteredSurvivors.join().duration,
272 result.duration,
273 timer.stop().getTime()
274 );
275
276 final int killCount =
277 filteredOffspring.join().result.killCount +
278 filteredSurvivors.join().result.killCount;
279
280 final int invalidCount =
281 filteredOffspring.join().result.invalidCount +
282 filteredSurvivors.join().result.invalidCount;
283
284 return EvolutionResult.of(
285 _optimize,
286 result.result,
287 start.generation,
288 durations,
289 killCount,
290 invalidCount,
291 alteredOffspring.join().result.alterCount
292 );
293 }
294
295 // Selects the survivors population. A new population object is returned.
296 private Population<G, C> selectSurvivors(final Population<G, C> population) {
297 return _survivorsSelector.select(population, _survivorsCount, _optimize);
298 }
299
300 // Selects the offspring population. A new population object is returned.
301 private Population<G, C> selectOffspring(final Population<G, C> population) {
302 return _offspringSelector.select(population, _offspringCount, _optimize);
303 }
304
305 // Filters out invalid and to old individuals. Filtering is done in place.
306 private FilterResult<G, C> filter(
307 final Population<G, C> population,
308 final long generation
309 ) {
310 int killCount = 0;
311 int invalidCount = 0;
312
313 for (int i = 0, n = population.size(); i < n; ++i) {
314 final Phenotype<G, C> individual = population.get(i);
315
316 if (!individual.isValid()) {
317 population.set(i, newPhenotype(generation));
318 ++invalidCount;
319 } else if (individual.getAge(generation) > _maximalPhenotypeAge) {
320 population.set(i, newPhenotype(generation));
321 ++killCount;
322 }
323 }
324
325 return new FilterResult<>(population, killCount, invalidCount);
326 }
327
328 // Create a new phenotype
329 private Phenotype<G, C> newPhenotype(final long generation) {
330 return Phenotype.of(
331 _genotypeFactory.newInstance(),
332 generation,
333 _fitnessFunction,
334 _fitnessScaler
335 );
336 }
337
338 // Alters the given population. The altering is done in place.
339 private AlterResult<G, C> alter(
340 final Population<G,C> population,
341 final long generation
342 ) {
343 return new AlterResult<>(
344 population,
345 _alterer.alter(population, generation)
346 );
347 }
348
349 // Evaluates the fitness function of the give population concurrently.
350 private Population<G, C> evaluate(final Population<G, C> population) {
351 try (Concurrency c = Concurrency.with(_executor.get())) {
352 c.execute(population);
353 }
354 return population;
355 }
356
357 /**
358 * Create a new <b>infinite</b> evolution iterator with a newly created
359 * population. This is an alternative way for evolution. It lets the user
360 * start, stop and resume the evolution process whenever desired.
361 *
362 * @return a new <b>infinite</b> evolution iterator
363 */
364 public Iterator<EvolutionResult<G, C>> iterator() {
365 return new EvolutionIterator<>(
366 this::evolve,
367 this::evolutionStart
368 );
369 }
370
371 /**
372 * Create a new <b>infinite</b> evolution stream with a newly created
373 * population.
374 *
375 * @return a new evolution stream.
376 */
377 public EvolutionStream<G, C> stream() {
378 return new EvolutionStreamImpl<>(
379 this::evolve,
380 this::evolutionStart
381 );
382 }
383
384 private EvolutionStart<G, C> evolutionStart() {
385 final int generation = 1;
386 final int size = _offspringCount + _survivorsCount;
387
388 final Population<G, C> population = new Population<G, C>(size)
389 .fill(() -> newPhenotype(generation), size);
390 evaluate(population);
391
392 return new EvolutionStart<>(population, generation);
393 }
394
395 /**
396 * Create a new <b>infinite</b> evolution stream with the given initial
397 * individuals. If an empty {@code Iterable} is given, the engines genotype
398 * factory is used for creating the population.
399 *
400 * @param genotypes the initial individuals used for the evolution stream.
401 * Missing individuals are created and individuals not needed are
402 * skipped.
403 * @return a new evolution stream.
404 * @throws java.lang.NullPointerException if the given {@code genotypes} is
405 * {@code null}.
406 */
407 public EvolutionStream<G, C> stream(
408 final Iterable<Genotype<G>> genotypes
409 ) {
410 requireNonNull(genotypes);
411
412 return new EvolutionStreamImpl<>(
413 this::evolve,
414 () -> evolutionStart(genotypes, 1)
415 );
416 }
417
418 /**
419 * Create a new <b>infinite</b> evolution iterator with the given initial
420 * individuals. If an empty {@code Iterable} is given, the engines genotype
421 * factory is used for creating the population.
422 *
423 * @param genotypes the initial individuals used for the evolution iterator.
424 * Missing individuals are created and individuals not needed are
425 * skipped.
426 * @return a new <b>infinite</b> evolution iterator
427 * @throws java.lang.NullPointerException if the given {@code genotypes} is
428 * {@code null}.
429 */
430 public Iterator<EvolutionResult<G, C>> iterator(
431 final Iterable<Genotype<G>> genotypes
432 ) {
433 requireNonNull(genotypes);
434
435 return new EvolutionIterator<>(
436 this::evolve,
437 () -> evolutionStart(genotypes, 1)
438 );
439 }
440
441 private EvolutionStart<G, C> evolutionStart(
442 final Iterable<Genotype<G>> genotypes,
443 final long generation
444 ) {
445 final Stream<Phenotype<G, C>> stream = Stream.concat(
446 StreamSupport.stream(genotypes.spliterator(), false)
447 .map(gt -> Phenotype.of(
448 gt, generation, _fitnessFunction, _fitnessScaler)),
449 Stream.generate(() -> newPhenotype(generation))
450 );
451
452 final Population<G, C> population = stream
453 .limit(getPopulationSize())
454 .collect(toPopulation());
455 evaluate(population);
456
457 return new EvolutionStart<>(population, generation);
458 }
459
460 /**
461 * Create a new <b>infinite</b> evolution stream with the given initial
462 * population. If an empty {@code Population} is given, the engines genotype
463 * factory is used for creating the population. The given population might
464 * be the result of an other engine and this method allows to start the
465 * evolution with the outcome of an different engine. The fitness function
466 * and the fitness scaler are replaced by the one defined for this engine.
467 *
468 * @param population the initial individuals used for the evolution stream.
469 * Missing individuals are created and individuals not needed are
470 * skipped.
471 * @param generation the generation the stream starts from; must be greater
472 * than zero.
473 * @return a new evolution stream.
474 * @throws java.lang.NullPointerException if the given {@code population} is
475 * {@code null}.
476 * @throws IllegalArgumentException if the given {@code generation} is smaller
477 * then one
478 */
479 public EvolutionStream<G, C> stream(
480 final Population<G, C> population,
481 final long generation
482 ) {
483 requireNonNull(population);
484 require.positive(generation);
485
486 return new EvolutionStreamImpl<>(
487 this::evolve,
488 () -> evolutionStart(population, generation)
489 );
490 }
491
492 /**
493 * Create a new <b>infinite</b> evolution iterator with the given initial
494 * population. If an empty {@code Population} is given, the engines genotype
495 * factory is used for creating the population. The given population might
496 * be the result of an other engine and this method allows to start the
497 * evolution with the outcome of an different engine. The fitness function
498 * and the fitness scaler are replaced by the one defined for this engine.
499 *
500 * @param population the initial individuals used for the evolution iterator.
501 * Missing individuals are created and individuals not needed are
502 * skipped.
503 * @param generation the generation the iterator starts from; must be greater
504 * than zero.
505 * @return a new <b>infinite</b> evolution iterator
506 * @throws java.lang.NullPointerException if the given {@code population} is
507 * {@code null}.
508 * @throws IllegalArgumentException if the given {@code generation} is smaller
509 * then one
510 */
511 public Iterator<EvolutionResult<G, C>> iterator(
512 final Population<G, C> population,
513 final long generation
514 ) {
515 requireNonNull(population);
516 require.positive(generation);
517
518 return new EvolutionIterator<>(
519 this::evolve,
520 () -> evolutionStart(population, generation)
521 );
522 }
523
524 private EvolutionStart<G, C> evolutionStart(
525 final Population<G, C> population,
526 final long generation
527 ) {
528 final Stream<Phenotype<G, C>> stream = Stream.concat(
529 population.stream()
530 .map(p -> p.newInstance(
531 p.getGeneration(),
532 _fitnessFunction,
533 _fitnessScaler)),
534 Stream.generate(() -> newPhenotype(generation))
535 );
536
537 final Population<G, C> pop = stream
538 .limit(getPopulationSize())
539 .collect(toPopulation());
540 evaluate(pop);
541
542 return new EvolutionStart<>(pop, generation);
543 }
544
545
546
547 /* *************************************************************************
548 * Property access methods.
549 **************************************************************************/
550
551 /**
552 * Return the fitness function of the GA engine.
553 *
554 * @return the fitness function
555 */
556 public Function<? super Genotype<G>, ? extends C> getFitnessFunction() {
557 return _fitnessFunction;
558 }
559
560 /**
561 * Return the fitness scaler of the GA engine.
562 *
563 * @return the fitness scaler
564 */
565 public Function<? super C, ? extends C> getFitnessScaler() {
566 return _fitnessScaler;
567 }
568
569 /**
570 * Return the used genotype {@link Factory} of the GA. The genotype factory
571 * is used for creating the initial population and new, random individuals
572 * when needed (as replacement for invalid and/or died genotypes).
573 *
574 * @return the used genotype {@link Factory} of the GA.
575 */
576 public Factory<Genotype<G>> getGenotypeFactory() {
577 return _genotypeFactory;
578 }
579
580 /**
581 * Return the used survivor {@link Selector} of the GA.
582 *
583 * @return the used survivor {@link Selector} of the GA.
584 */
585 public Selector<G, C> getSurvivorsSelector() {
586 return _survivorsSelector;
587 }
588
589 /**
590 * Return the used offspring {@link Selector} of the GA.
591 *
592 * @return the used offspring {@link Selector} of the GA.
593 */
594 public Selector<G, C> getOffspringSelector() {
595 return _offspringSelector;
596 }
597
598 /**
599 * Return the used {@link Alterer} of the GA.
600 *
601 * @return the used {@link Alterer} of the GA.
602 */
603 public Alterer<G, C> getAlterer() {
604 return _alterer;
605 }
606
607 /**
608 * Return the number of selected offsprings.
609 *
610 * @return the number of selected offsprings
611 */
612 public int getOffspringCount() {
613 return _offspringCount;
614 }
615
616 /**
617 * The number of selected survivors.
618 *
619 * @return the number of selected survivors
620 */
621 public int getSurvivorsCount() {
622 return _survivorsCount;
623 }
624
625 /**
626 * Return the number of individuals of a population.
627 *
628 * @return the number of individuals of a population
629 */
630 public int getPopulationSize() {
631 return _offspringCount + _survivorsCount;
632 }
633
634 /**
635 * Return the maximal allowed phenotype age.
636 *
637 * @return the maximal allowed phenotype age
638 */
639 public long getMaximalPhenotypeAge() {
640 return _maximalPhenotypeAge;
641 }
642
643 /**
644 * Return the optimization strategy.
645 *
646 * @return the optimization strategy
647 */
648 public Optimize getOptimize() {
649 return _optimize;
650 }
651
652
653 /* *************************************************************************
654 * Builder methods.
655 **************************************************************************/
656
657 /**
658 * Create a new evolution {@code Engine.Builder} initialized with the values
659 * of the current evolution {@code Engine}. With this method, the evolution
660 * engine can serve as a template for an new one.
661 *
662 * @return a new engine builder
663 */
664 public Builder<G, C> builder() {
665 return new Builder<>(_genotypeFactory, _fitnessFunction)
666 .alterers(_alterer)
667 .clock(_clock)
668 .executor(_executor.get())
669 .fitnessScaler(_fitnessScaler)
670 .maximalPhenotypeAge(_maximalPhenotypeAge)
671 .offspringFraction((double)_offspringCount/(double)getPopulationSize())
672 .offspringSelector(_offspringSelector)
673 .optimize(_optimize)
674 .populationSize(getPopulationSize())
675 .survivorsSelector(_survivorsSelector);
676 }
677
678 /**
679 * Create a new evolution {@code Engine.Builder} with the given fitness
680 * function and genotype factory.
681 *
682 * @param fitnessFunction the fitness function
683 * @param genotypeFactory the genotype factory
684 * @param <G> the gene type
685 * @param <C> the fitness function result type
686 * @return a new engine builder
687 * @throws java.lang.NullPointerException if one of the arguments is
688 * {@code null}.
689 */
690 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
691 Builder<G, C> builder(
692 final Function<? super Genotype<G>, ? extends C> fitnessFunction,
693 final Factory<Genotype<G>> genotypeFactory
694 ) {
695 return new Builder<>(genotypeFactory, fitnessFunction);
696 }
697
698 /**
699 * Create a new evolution {@code Engine.Builder} with the given fitness
700 * function and chromosome templates.
701 *
702 * @param fitnessFunction the fitness function
703 * @param chromosome the first chromosome
704 * @param chromosomes the chromosome templates
705 * @param <G> the gene type
706 * @param <C> the fitness function result type
707 * @return a new engine builder
708 * @throws java.lang.NullPointerException if one of the arguments is
709 * {@code null}.
710 */
711 @SafeVarargs
712 public static <G extends Gene<?, G>, C extends Comparable<? super C>>
713 Builder<G, C> builder(
714 final Function<? super Genotype<G>, ? extends C> fitnessFunction,
715 final Chromosome<G> chromosome,
716 final Chromosome<G>... chromosomes
717 ) {
718 return new Builder<>(
719 Genotype.of(chromosome, chromosomes),
720 fitnessFunction
721 );
722 }
723
724
725
726 /* *************************************************************************
727 * Inner classes
728 **************************************************************************/
729
730 /**
731 * Builder class for building GA {@code Engine} instances.
732 *
733 * @see Engine
734 *
735 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
736 * @since 3.0
737 * @version 3.0 — <em>$Date: 2014-12-28 $</em>
738 */
739 public static final class Builder<
740 G extends Gene<?, G>,
741 C extends Comparable<? super C>
742 >
743 {
744
745 // No default values for this properties.
746 private Function<? super Genotype<G>, ? extends C> _fitnessFunction;
747 private Factory<Genotype<G>> _genotypeFactory;
748
749 // This are the properties which default values.
750 private Function<? super C, ? extends C> _fitnessScaler = a -> a;
751 private Selector<G, C> _survivorsSelector = new TournamentSelector<>(3);
752 private Selector<G, C> _offspringSelector = new TournamentSelector<>(3);
753 private Alterer<G, C> _alterer = Alterer.of(
754 new SinglePointCrossover<G, C>(0.2),
755 new Mutator<>(0.15)
756 );
757 private Optimize _optimize = Optimize.MAXIMUM;
758 private double _offspringFraction = 0.6;
759 private int _populationSize = 50;
760 private long _maximalPhenotypeAge = 70;
761
762 private Executor _executor = ForkJoinPool.commonPool();
763 private Clock _clock = NanoClock.INSTANCE;
764
765 private Builder(
766 final Factory<Genotype<G>> genotypeFactory,
767 final Function<? super Genotype<G>, ? extends C> fitnessFunction
768 ) {
769 _genotypeFactory = requireNonNull(genotypeFactory);
770 _fitnessFunction = requireNonNull(fitnessFunction);
771 }
772
773 /**
774 * Set the fitness function of the evolution {@code Engine}.
775 *
776 * @param function the fitness function to use in the GA {@code Engine}
777 * @return {@code this} builder, for command chaining
778 */
779 public Builder<G, C> fitnessFunction(
780 Function<? super Genotype<G>, ? extends C> function
781 ) {
782 _fitnessFunction = requireNonNull(function);
783 return this;
784 }
785
786 /**
787 * Set the fitness scaler of the evolution {@code Engine}. <i>Default
788 * value is set to the identity function.</i>
789 *
790 * @param scaler the fitness scale to use in the GA {@code Engine}
791 * @return {@code this} builder, for command chaining
792 */
793 public Builder<G, C> fitnessScaler(
794 final Function<? super C, ? extends C> scaler
795 ) {
796 _fitnessScaler = requireNonNull(scaler);
797 return this;
798 }
799
800 /**
801 * The genotype factory used for creating new individuals.
802 *
803 * @param genotypeFactory the genotype factory for creating new
804 * individuals.
805 * @return {@code this} builder, for command chaining
806 */
807 public Builder<G, C> genotypeFactory(
808 final Factory<Genotype<G>> genotypeFactory
809 ) {
810 _genotypeFactory = requireNonNull(genotypeFactory);
811 return this;
812 }
813
814 /**
815 * The selector used for selecting the offspring population. <i>Default
816 * values is set to {@code TournamentSelector<>(3)}.</i>
817 *
818 * @param selector used for selecting the offspring population
819 * @return {@code this} builder, for command chaining
820 */
821 public Builder<G, C> offspringSelector(
822 final Selector<G, C> selector
823 ) {
824 _offspringSelector = requireNonNull(selector);
825 return this;
826 }
827
828 /**
829 * The selector used for selecting the survivors population. <i>Default
830 * values is set to {@code TournamentSelector<>(3)}.</i>
831 *
832 * @param selector used for selecting survivors population
833 * @return {@code this} builder, for command chaining
834 */
835 public Builder<G, C> survivorsSelector(
836 final Selector<G, C> selector
837 ) {
838 _survivorsSelector = requireNonNull(selector);
839 return this;
840 }
841
842 /**
843 * The selector used for selecting the survivors and offspring
844 * population. <i>Default values is set to
845 * {@code TournamentSelector<>(3)}.</i>
846 *
847 * @param selector used for selecting survivors and offspring population
848 * @return {@code this} builder, for command chaining
849 */
850 public Builder<G, C> selector(final Selector<G, C> selector) {
851 _offspringSelector = requireNonNull(selector);
852 _survivorsSelector = requireNonNull(selector);
853 return this;
854 }
855
856 /**
857 * The alterers used for alter the offspring population. <i>Default
858 * values is set to {@code new SinglePointCrossover<>(0.2)} followed by
859 * {@code new Mutator<>(0.15)}.</i>
860 *
861 * @param first the first alterer used for alter the offspring
862 * population
863 * @param rest the rest of the alterers used for alter the offspring
864 * population
865 * @return {@code this} builder, for command chaining
866 * @throws java.lang.NullPointerException if one of the alterers is
867 * {@code null}.
868 */
869 @SafeVarargs
870 public final Builder<G, C> alterers(
871 final Alterer<G, C> first,
872 final Alterer<G, C>... rest
873 ) {
874 requireNonNull(first);
875 Stream.of(rest).forEach(Objects::requireNonNull);
876
877 _alterer = rest.length == 0 ?
878 first :
879 Alterer.of(rest).compose(first);
880
881 return this;
882 }
883
884 /**
885 * The optimization strategy used by the engine. <i>Default values is
886 * set to {@code Optimize.MAXIMUM}.</i>
887 *
888 * @param optimize the optimization strategy used by the engine
889 * @return {@code this} builder, for command chaining
890 */
891 public Builder<G, C> optimize(final Optimize optimize) {
892 _optimize = requireNonNull(optimize);
893 return this;
894 }
895
896 /**
897 * The offspring fraction. <i>Default values is set to {@code 0.6}.</i>
898 *
899 * @param fraction the offspring fraction
900 * @return {@code this} builder, for command chaining
901 * @throws java.lang.IllegalArgumentException if the fraction is not
902 * within the range [0, 1].
903 */
904 public Builder<G, C> offspringFraction(final double fraction) {
905 _offspringFraction = probability(fraction);
906 return this;
907 }
908
909 /**
910 * The number of individuals which form the population. <i>Default
911 * values is set to {@code 50}.</i>
912 *
913 * @param size the number of individuals of a population
914 * @return {@code this} builder, for command chaining
915 * @throws java.lang.IllegalArgumentException if {@code size < 1}
916 */
917 public Builder<G, C> populationSize(final int size) {
918 if (size < 1) {
919 throw new IllegalArgumentException(format(
920 "Population size must be greater than zero, but was %s.", size
921 ));
922 }
923 _populationSize = size;
924 return this;
925 }
926
927 /**
928 * The maximal allowed age of a phenotype. <i>Default values is set to
929 * {@code 70}.</i>
930 *
931 * @param age the maximal phenotype age
932 * @return {@code this} builder, for command chaining
933 * @throws java.lang.IllegalArgumentException if {@code age < 1}
934 */
935 public Builder<G, C> maximalPhenotypeAge(final long age) {
936 if (age < 1) {
937 throw new IllegalArgumentException(format(
938 "Phenotype age must be greater than one, but was %s.", age
939 ));
940 }
941 _maximalPhenotypeAge = age;
942 return this;
943 }
944
945 /**
946 * The executor used by the engine.
947 *
948 * @param executor the executor used by the engine
949 * @return {@code this} builder, for command chaining
950 */
951 public Builder<G, C> executor(final Executor executor) {
952 _executor = requireNonNull(executor);
953 return this;
954 }
955
956 /**
957 * The clock used for calculating the execution durations.
958 *
959 * @param clock the clock used for calculating the execution durations
960 * @return {@code this} builder, for command chaining
961 */
962 public Builder<G, C> clock(final Clock clock) {
963 _clock = requireNonNull(clock);
964 return this;
965 }
966
967 /**
968 * Builds an new {@code Engine} instance from the set properties.
969 *
970 * @return an new {@code Engine} instance from the set properties
971 */
972 public Engine<G, C> build() {
973 return new Engine<>(
974 _fitnessFunction,
975 _fitnessScaler,
976 _genotypeFactory,
977 _survivorsSelector,
978 _offspringSelector,
979 _alterer,
980 _optimize,
981 getOffspringCount(),
982 getSurvivorsCount(),
983 _maximalPhenotypeAge,
984 _executor,
985 _clock
986 );
987 }
988
989 private int getSurvivorsCount() {
990 return _populationSize - getOffspringCount();
991 }
992
993 private int getOffspringCount() {
994 return (int)round(_offspringFraction*_populationSize);
995 }
996
997 }
998 }
|