1 package net.bmahe.genetics4j.core.postevaluationprocess;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.function.BiFunction;
7 import java.util.function.Function;
8
9 import org.apache.commons.lang3.Validate;
10 import org.immutables.value.Value;
11
12 import net.bmahe.genetics4j.core.Genotype;
13 import net.bmahe.genetics4j.core.Individual;
14 import net.bmahe.genetics4j.core.Population;
15 import net.bmahe.genetics4j.core.spec.PostEvaluationProcessor;
16
17 @Value.Immutable
18 public abstract class FitnessSharing<T extends Comparable<T>> implements PostEvaluationProcessor<T> {
19
20 @Value.Parameter
21 public abstract BiFunction<Genotype, Genotype, Double> distance();
22
23 @Value.Parameter
24 public abstract Function<Double, Double> sharing();
25
26 @Value.Parameter
27 public abstract BiFunction<Individual<T>, Double, T> scaleFitness();
28
29 @Override
30 public Population<T> apply(final long generation, final Population<T> population) {
31 Validate.isTrue(generation >= 0);
32 Objects.requireNonNull(population);
33
34 if (population.isEmpty()) {
35 return population;
36 }
37
38 final List<T> newFitness = new ArrayList<>();
39 for (int i = 0; i < population.size(); i++) {
40 final Genotype genotypeI = population.getGenotype(i);
41 final Individual<T> individual = population.getIndividual(i);
42
43 double sumSharing = 0.0d;
44 for (int j = 0; j < population.size(); j++) {
45 final Genotype genotypeJ = population.getGenotype(j);
46
47 final double distance = distance().apply(genotypeI, genotypeJ);
48 final double sharing = sharing().apply(distance);
49 sumSharing += sharing;
50 }
51
52 final T newFitnessI = scaleFitness().apply(individual, sumSharing);
53 newFitness.add(newFitnessI);
54 }
55
56 return Population.<T>of(population.getAllGenotypes(), newFitness);
57 }
58
59 public static FitnessSharing<Double> of(final BiFunction<Genotype, Genotype, Double> distance,
60 final Function<Double, Double> sharing) {
61 return ImmutableFitnessSharing
62 .of(distance, sharing, (individual, sumSharing) -> individual.fitness() / sumSharing);
63 }
64
65 public static FitnessSharing<Double> ofStandard(final BiFunction<Genotype, Genotype, Double> distance,
66 final double sigma) {
67 return FitnessSharing.of(distance, (d) -> {
68 if (d < 0.0 || d > sigma) {
69 return 0.0;
70 }
71
72 return 1 - d / sigma;
73 });
74 }
75
76 public static FitnessSharing<Double> ofStandard(final BiFunction<Genotype, Genotype, Double> distance,
77 final double sigma, final double alpha) {
78 return FitnessSharing.of(distance, (d) -> {
79 if (d < 0.0 || d > sigma) {
80 return 0.0;
81 }
82
83 return 1 - Math.pow(d / sigma, alpha);
84 });
85 }
86
87 public static FitnessSharing<Float> ofFloatFitness(final BiFunction<Genotype, Genotype, Double> distance,
88 final Function<Double, Double> sharing) {
89 return ImmutableFitnessSharing
90 .of(distance, sharing, (individual, sumSharing) -> (float) (individual.fitness() / sumSharing));
91 }
92 }