View Javadoc
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 }