1 package net.bmahe.genetics4j.gp.postevaluationprocess;
2
3 import java.util.Objects;
4 import java.util.function.Function;
5 import java.util.random.RandomGenerator;
6
7 import org.apache.commons.lang3.Validate;
8 import org.immutables.value.Value;
9
10 import net.bmahe.genetics4j.core.Genotype;
11 import net.bmahe.genetics4j.core.Population;
12 import net.bmahe.genetics4j.core.chromosomes.TreeChromosome;
13 import net.bmahe.genetics4j.core.spec.PostEvaluationProcessor;
14
15 @Value.Immutable
16 public abstract class TarpeianMethod implements PostEvaluationProcessor<Double> {
17
18 @Value.Parameter
19 public abstract RandomGenerator randomGenerator();
20
21 @Value.Parameter
22 public abstract Function<Genotype, Integer> sizeFunction();
23
24 @Value.Parameter
25 public abstract double probability();
26
27 @Value.Parameter
28 public abstract double newValue();
29
30 @Value.Check
31 protected void check() {
32 Validate.inclusiveBetween(0.0d, 1.0d, probability());
33 }
34
35 @Override
36 public Population<Double> apply(final long generation, final Population<Double> population) {
37 Validate.isTrue(generation >= 0);
38 Objects.requireNonNull(population);
39
40 if (population.isEmpty()) {
41 return population;
42 }
43
44 final double averageSize = population.getAllGenotypes()
45 .stream()
46 .map(genotype -> sizeFunction().apply(genotype))
47 .mapToInt(i -> i)
48 .average()
49 .getAsDouble();
50
51 final Population<Double> newPopulation = new Population<>();
52 for (int i = 0; i < population.size(); i++) {
53
54 final Genotype genotype = population.getGenotype(i);
55 final int size = sizeFunction().apply(genotype);
56
57 double fitness = population.getFitness(i);
58 if (size > averageSize && randomGenerator().nextDouble() < probability()) {
59 fitness = newValue();
60 }
61
62 newPopulation.add(genotype, fitness);
63 }
64
65 return newPopulation;
66 }
67
68 public static TarpeianMethod of(final RandomGenerator randomGenerator,
69 final Function<Genotype, Integer> sizeFunction, final double probability, final double newValue) {
70 return ImmutableTarpeianMethod.of(randomGenerator, sizeFunction, probability, newValue);
71 }
72
73 public static TarpeianMethod ofTreeChromosome(final RandomGenerator randomGenerator, final int chromosomeIndex,
74 final double probability, final double newValue) {
75
76 return ImmutableTarpeianMethod.of(
77 randomGenerator,
78 genotype -> genotype.getChromosome(chromosomeIndex, TreeChromosome.class).getSize(),
79 probability,
80 newValue);
81 }
82 }