1 package net.bmahe.genetics4j.core.spec;
2
3 import java.util.Comparator;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.Optional;
7 import java.util.stream.IntStream;
8
9 import org.apache.commons.lang3.Validate;
10 import org.immutables.value.Value;
11
12 import net.bmahe.genetics4j.core.Genotype;
13
14 @Value.Immutable
15 public abstract class EvolutionResult<T extends Comparable<T>> {
16
17 @Value.Parameter
18 public abstract AbstractEAConfiguration<T> eaConfiguration();
19
20 @Value.Parameter
21 public abstract long generation();
22
23 @Value.Parameter
24 public abstract List<Genotype> population();
25
26 @Value.Parameter
27 public abstract List<T> fitness();
28
29 @Value.Derived
30 public GenotypeFitness<T> bestIndividual() {
31
32 final List<Genotype> population = population();
33 final List<T> fitness = fitness();
34
35 Objects.requireNonNull(population);
36 Objects.requireNonNull(fitness);
37 Validate.isTrue(population.size() == fitness.size());
38 Validate.isTrue(population.isEmpty() == false, "population cannot be empty");
39
40 final Comparator<T> comparator = eaConfiguration().fitnessComparator();
41
42 final Optional<Integer> bestIndexOpt = IntStream.range(0, fitness.size())
43 .boxed()
44 .max((a, b) -> comparator.compare(fitness.get(a), fitness.get(b)));
45
46 final Integer bestIndex = bestIndexOpt.orElseThrow(
47 () -> new IllegalStateException("Couldn't find a best entry despite having a non-zero population"));
48
49 return GenotypeFitness.of(population.get(bestIndex), fitness.get(bestIndex));
50 }
51
52 public Genotype bestGenotype() {
53 return bestIndividual().genotype();
54 }
55
56 public T bestFitness() {
57 return bestIndividual().fitness();
58 }
59 }