
fr.vergne.optimization.population.impl.CompetitionManager Maven / Gradle / Ivy
The newest version!
package fr.vergne.optimization.population.impl;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import fr.vergne.optimization.generator.Mutator;
import fr.vergne.optimization.population.PopulationManager;
/**
* This {@link CompetitionManager} aims at keeping only the best candidates, by
* removing all the losers of a {@link Competition}. Each time a new
* {@link Individual} is provided by {@link #push(Object)}, a competition
* occurs. If the new {@link Individual} does not perform better, it is removed,
* otherwise it is kept with potential other winners. The method
* {@link #getScore(Object)} allows to know how many competitions each
* {@link Individual} has won.
*
* The method {@link #setCompetitors(Collection)} can be used to consider
* specific {@link Individual}s during the competition. For instance, if the new
* {@link Individual} has been generated by a {@link Mutator}, one can want to
* make compete the original {@link Individual} with its mutant. As long as this
* method is not re-used, the competitors are the previous winners (i.e. all the
* current population by default).
*
* @author Matthieu Vergne
*
* @param
* @param
*/
public class CompetitionManager implements
PopulationManager {
private final Collection competitors = new HashSet();
private final Map> scores = new HashMap>();
private final Competition competition;
private Tournament currentTournament = null;
private Map maxScoreGlobal = new HashMap();
public CompetitionManager(Competition competition) {
this.competition = competition;
}
/**
*
* @param competitors
* the {@link Individual}s to consider in the next competition
*/
public void setCompetitors(Collection candidates) {
competitors.clear();
for (Individual candidate : candidates) {
if (getPopulation().contains(candidate)) {
competitors.add(candidate);
} else {
throw new IllegalArgumentException(
"Candidate not in the current population: " + candidate);
}
}
}
/**
*
* @param tournament
* the current {@link Tournament}
*/
public void setCurrentTournament(Tournament tournament) {
this.currentTournament = tournament;
}
/**
*
* @return the current {@link Tournament}
*/
public Tournament getCurrentTournament() {
return currentTournament;
}
@Override
public void push(Individual individual) {
competitors.add(individual);
Collection winners = new HashSet(
competition.compete(competitors));
Collection losers = new HashSet(competitors);
losers.removeAll(winners);
for (Individual winner : winners) {
Integer score = getScore(currentTournament, winner);
setScore(currentTournament, winner, score + 1);
}
for (Individual loser : losers) {
competitors.remove(loser);
scores.remove(loser);
}
}
@Override
public Collection getPopulation() {
return scores.keySet();
}
/**
* This method is a shortcut to getPopulation().size()
.
*
* @return the size of the current population
*/
public int size() {
return getPopulation().size();
}
@Override
public Iterator getBest() {
return new Iterator() {
LinkedList winners = new LinkedList();
Set remaining = new HashSet(getPopulation());
@Override
public boolean hasNext() {
return !remaining.isEmpty() || !winners.isEmpty();
}
@Override
public Individual next() {
if (hasNext()) {
if (winners.isEmpty()) {
winners.addAll(competition.compete(remaining));
remaining.removeAll(winners);
} else {
// consider the remaining winners
}
return winners.removeFirst();
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
*
* @param tournament
* the {@link Tournament} to consider
* @param individual
* an {@link Individual}
* @return the number of competitions won by this {@link Individual} for
* this specific {@link Tournament}, 0 by default
*/
public Integer getScore(Tournament tournament, Individual individual) {
Map individualScores = retrieveIndividualScores(individual);
return individualScores.containsKey(tournament) ? individualScores
.get(tournament) : 0;
}
/**
*
* @param tournament
* the {@link Tournament} to consider
* @param individual
* an {@link Individual}
* @param score
* the score of this {@link Individual} for this specific
* {@link Tournament}
*/
public void setScore(Tournament tournament, Individual individual, int score) {
retrieveIndividualScores(individual).put(tournament, score);
int currentMax = maxScoreGlobal.containsKey(tournament) ? maxScoreGlobal
.get(tournament) : 0;
maxScoreGlobal.put(tournament, Math.max(score, currentMax));
}
private Map retrieveIndividualScores(
Individual individual) {
Map individualScores = scores.get(individual);
if (individualScores == null) {
individualScores = new HashMap();
scores.put(individual, individualScores);
} else {
// use the one retrieved
}
return individualScores;
}
/**
*
* @param tournament
* the {@link Tournament} to consider
* @return the smallest score for the given {@link Tournament} in the
* current population, null
if the population is empty
*/
public Integer getMinScore(Tournament tournament) {
Integer minScore = Integer.MAX_VALUE;
for (Map individualScores : scores.values()) {
if (individualScores.containsKey(tournament)) {
minScore = Math.min(minScore, individualScores.get(tournament));
} else {
continue;
}
}
return minScore == Integer.MAX_VALUE ? null : minScore;
}
/**
*
* @param tournament
* the {@link Tournament} to consider
* @return the highest score for the given {@link Tournament} in the current
* population, null
if the population is empty
*/
public Integer getMaxScore(Tournament tournament) {
Integer maxScore = -1;
for (Map individualScores : scores.values()) {
if (individualScores.containsKey(tournament)) {
maxScore = Math.max(maxScore, individualScores.get(tournament));
} else {
continue;
}
}
return maxScore == -1 ? null : maxScore;
}
/**
*
* @param tournament
* the {@link Tournament} to consider
* @return the highest score reached since the beginning for this
* {@link Tournament}
*/
public int getMaxScoreGlobal(Tournament tournament) {
return maxScoreGlobal.containsKey(tournament) ? maxScoreGlobal
.get(tournament) : 0;
}
public Iterator> getScoreDescriptors() {
return new Iterator>() {
private final Iterator tournaments = maxScoreGlobal
.keySet().iterator();
private ScoreDescriptor next = null;
@Override
public boolean hasNext() {
findNextIfNecessary();
return next != null;
}
@Override
public ScoreDescriptor next() {
findNextIfNecessary();
ScoreDescriptor descriptor = next;
next = null;
return descriptor;
}
private void findNextIfNecessary() {
while (tournaments.hasNext() && next == null) {
Tournament tournament = tournaments.next();
try {
int min = getMinScore(tournament);
int max = getMaxScore(tournament);
next = new ScoreDescriptor(tournament, min,
max);
} catch (NullPointerException e) {
continue;
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* A {@link ScoreDescriptor} provide detailed information about scores as
* returned by {@link CompetitionManager#getScore(Object, Object)} and
* related methods.
*
* @author Matthieu Vergne
*
*/
public static class ScoreDescriptor {
private final int min;
private final int max;
private final Tournament tournament;
public ScoreDescriptor(Tournament tournament, int min, int max) {
this.tournament = tournament;
this.min = min;
this.max = max;
}
public Tournament getTournament() {
return tournament;
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
public double getRatio() {
return min == 0 ? 0 : (double) min / max;
}
}
/**
* A {@link Competition} aims at making competing {@link Individual}s in
* order to differentiate winners/losers.
*
* @author Matthieu Vergne
*
* @param
*/
public static interface Competition {
/**
* This method should return all the winners among the competitors. It
* can contain all the competitors, but not be empty. If no winner/loser
* can be identified, all the competitors should be returned. If several
* winners are returned, it means that none of them perform better than
* the other winners.
*
* @param competitors
* the {@link Individual}s to make compete
* @return the winning {@link Individual}s
*/
public Collection compete(Collection competitors);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy