1 package net.bmahe.genetics4j.core.selection;
2
3 import java.util.Comparator;
4 import java.util.List;
5 import java.util.Objects;
6 import java.util.random.RandomGenerator;
7 import java.util.stream.IntStream;
8
9 import org.apache.commons.lang3.Validate;
10 import org.apache.logging.log4j.LogManager;
11 import org.apache.logging.log4j.Logger;
12
13 import net.bmahe.genetics4j.core.Genotype;
14 import net.bmahe.genetics4j.core.Individual;
15 import net.bmahe.genetics4j.core.Population;
16 import net.bmahe.genetics4j.core.spec.AbstractEAConfiguration;
17 import net.bmahe.genetics4j.core.spec.selection.SelectiveRefinementTournament;
18 import net.bmahe.genetics4j.core.spec.selection.Tournament;
19 import net.bmahe.genetics4j.core.util.IndividualUtils;
20
21 public class SelectiveRefinementTournamentSelector<T extends Comparable<T>> implements Selector<T> {
22 final static public Logger logger = LogManager.getLogger(SelectiveRefinementTournamentSelector.class);
23
24 private final SelectiveRefinementTournament<T> selectiveRefinementTournament;
25 private final RandomGenerator randomGenerator;
26
27 public SelectiveRefinementTournamentSelector(final SelectiveRefinementTournament<T> _selectiveRefinementTournament,
28 final RandomGenerator _randomGenerator) {
29 Objects.requireNonNull(_selectiveRefinementTournament);
30 Objects.requireNonNull(_randomGenerator);
31
32 this.selectiveRefinementTournament = _selectiveRefinementTournament;
33 this.randomGenerator = _randomGenerator;
34 }
35
36 protected Individual<T> randomIndividual(final List<Genotype> population, final List<T> fitnessScore) {
37 Objects.requireNonNull(population);
38 Objects.requireNonNull(fitnessScore);
39 Validate.isTrue(fitnessScore.size() > 0);
40 Validate.isTrue(population.size() == fitnessScore.size());
41
42 final int candidateIndex = randomGenerator.nextInt(fitnessScore.size());
43 return Individual.of(population.get(candidateIndex), fitnessScore.get(candidateIndex));
44
45 }
46
47 protected Individual<T> selectForFitness(final AbstractEAConfiguration<T> eaConfiguration,
48 final Comparator<Individual<T>> fitnessComparator, final int numCandidates, final List<Genotype> population,
49 final List<T> fitnessScore) {
50 Objects.requireNonNull(population);
51 Objects.requireNonNull(fitnessScore);
52 Validate.isTrue(fitnessScore.isEmpty() == false);
53
54 return IntStream.range(0, numCandidates)
55 .boxed()
56 .map(i -> randomIndividual(population, fitnessScore))
57 .max((a, b) -> fitnessComparator.compare(a, b))
58 .get();
59 }
60
61 protected Individual<T> selectForRefinement(final Comparator<Individual<T>> refinementComparator,
62 final Individual<T> candidateA, final Individual<T> candidateB) {
63 Objects.requireNonNull(refinementComparator);
64 Objects.requireNonNull(candidateA);
65 Objects.requireNonNull(candidateB);
66
67 int compared = refinementComparator.compare(candidateA, candidateB);
68 if (compared < 0) {
69 return candidateB;
70 } else if (compared > 0) {
71 return candidateA;
72 }
73 return randomGenerator.nextFloat() < 0.5 ? candidateA : candidateB;
74 }
75
76 @Override
77 public Population<T> select(final AbstractEAConfiguration<T> eaConfiguration, final long generation,
78 final int numIndividuals, final List<Genotype> population, final List<T> fitnessScore) {
79 Objects.requireNonNull(eaConfiguration);
80 Objects.requireNonNull(population);
81 Objects.requireNonNull(fitnessScore);
82 Validate.isTrue(generation >= 0);
83 Validate.isTrue(numIndividuals > 0);
84 Validate.isTrue(population.size() == fitnessScore.size());
85
86 final Tournament<T> tournament = selectiveRefinementTournament.tournament();
87 final Comparator<Individual<T>> refinementComparator = selectiveRefinementTournament.refinementComparator();
88 final float refinementRatio = selectiveRefinementTournament.refinementRatio();
89
90 final Comparator<Individual<T>> fitnessComparator = IndividualUtils.fitnessBasedComparator(eaConfiguration);
91
92 logger.debug("Selecting {} individuals", numIndividuals);
93
94 final Population<T> selectedIndividuals = new Population<>();
95
96 while (selectedIndividuals.size() < numIndividuals) {
97
98 final Individual<T> first = selectForFitness(eaConfiguration,
99 fitnessComparator,
100 tournament.numCandidates(),
101 population,
102 fitnessScore);
103 final Individual<T> second = selectForFitness(eaConfiguration,
104 fitnessComparator,
105 tournament.numCandidates(),
106 population,
107 fitnessScore);
108
109 final Individual<T> selected = randomGenerator.nextFloat() < refinementRatio
110 ? selectForRefinement(refinementComparator, first, second)
111 : (fitnessComparator.compare(first, second) < 0 ? second : first);
112
113 selectedIndividuals.add(selected);
114 }
115
116 return selectedIndividuals;
117 }
118 }