
fr.vergne.optimization.population.impl.OptimizerPool Maven / Gradle / Ivy
The newest version!
package fr.vergne.optimization.population.impl;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import fr.vergne.logging.LoggerConfiguration;
import fr.vergne.optimization.generator.InformedMutator;
import fr.vergne.optimization.generator.Mutator;
import fr.vergne.optimization.population.PopulationManager;
import fr.vergne.optimization.population.impl.OptimizerPool.Optimizer;
/**
* An {@link OptimizerPool} is a simple collection of {@link Optimizer}s with a
* common {@link Competition} process. This commonality allows to use the same
* evaluation process between the {@link Individual}s of each {@link Optimizer},
* providing a consistent comparison. It is especially used to sort the
* representatives of the different {@link Optimizer}s for the method
* {@link #getBest()}.
*
* @author Matthieu Vergne
*
* @param
*/
public class OptimizerPool implements
Iterable>, PopulationManager {
private final Collection> optimizers = new LinkedList>();
private Competition competition;
private OptimalityChecker optimalityCheker = null;
public OptimizerPool() {
}
public OptimizerPool(Competition competition) {
setCompetition(competition);
}
public void setCompetition(Competition competition) {
if (competition == null) {
throw new IllegalArgumentException(
"You must provide a competition operator.");
} else if (competition.equals(this.competition)) {
// ignore the change to not loose valuable data
} else {
this.competition = competition;
for (Optimizer optimizer : optimizers) {
optimizer.reset();
}
}
}
public Competition getCompetition() {
return competition;
}
public void setOptimalityCheker(
OptimalityChecker optimalityCheker) {
this.optimalityCheker = optimalityCheker;
}
public OptimalityChecker getOptimalityCheker() {
return optimalityCheker;
}
@Override
public Collection getPopulation() {
Collection population = new LinkedList();
for (Optimizer optimizer : optimizers) {
population.add(optimizer.getRepresentative());
}
return population;
}
/**
* Remove all the current {@link Optimizer}s.
*/
public void clear() {
optimizers.clear();
}
@Override
public Iterator> iterator() {
return optimizers.iterator();
}
@Override
public void push(Individual individual) {
optimizers.add(new Optimizer(individual, this));
}
public void remove(Individual individual) {
Iterator> iterator = optimizers.iterator();
while (iterator.hasNext()) {
Optimizer optimizer = iterator.next();
if (optimizer.getRepresentative().equals(individual)) {
iterator.remove();
return;
} else {
continue;
}
}
}
public int size() {
return optimizers.size();
}
@Override
public Iterator getBest() {
return new Iterator() {
private final List remaining = new LinkedList(
getPopulation());
private Individual best;
@Override
public boolean hasNext() {
return !remaining.isEmpty();
}
@Override
public Individual next() {
Iterator iterator = remaining.iterator();
best = iterator.next();
while (iterator.hasNext()) {
Individual winner = competition.compete(best,
iterator.next());
best = winner == null ? best : winner;
}
remaining.remove(best);
return best;
}
@Override
public void remove() {
OptimizerPool.this.remove(best);
}
};
}
/**
* An {@link Optimizer} aims at finding an optimal {@link Individual} (local
* optimum) by exploiting {@link Mutator}s to find better solutions. Each
* {@link Mutator} defines a specific topology over the space of
* {@link Individual}s, and using one {@link Mutator} while keeping only the
* best {@link Individual} generated allows to converge quickly to such
* optimal {@link Individual}. By using several {@link Mutator}s, a broader
* topology is involved, increasing the chance to find better
* {@link Individual}s, although it does not ensure to find a global
* optimum. More details are provided in the documentation of
* {@link #getOptimalityWith(Mutator)}.
*
* @author Matthieu Vergne
*
* @param
*/
public static class Optimizer {
private final Map, Individual> neighborReferences = new HashMap, Individual>();
private final Map, Integer> neighborLoops = new HashMap, Integer>();
private final Map, Integer> neighborCounts = new HashMap, Integer>();
private final OptimizerPool parentPool;
private Individual representative;
public static final Logger logger = LoggerConfiguration
.getSimpleLogger();
public Optimizer(Individual individual, OptimizerPool parent) {
representative = individual;
parentPool = parent;
}
/**
* This method aims at evaluating the degree of optimality of the
* current representative of this {@link Optimizer}. This optimality
* corresponds to the probability to not be improved by a given
* {@link Mutator}.
*
* More formally, each {@link Mutator} generates a mutant, among a set
* of possible mutants which depends on the original {@link Individual}
* provided. This set of mutants can be described as direct neighbors of
* the original {@link Individual}, where the neighboring is defined by
* the {@link Mutator} used. Thus, the {@link Mutator} acts similarly to
* a topology
* over the set of {@link Individual}s, excepted that the
* {@link Individual} is not necessarily in its own neighborhoods (i.e.
* one of the possible mutants).
*
* Given that a {@link Mutator} is used to find better
* {@link Individual}s within this neighborhood, an {@link Individual}
* is optimal regarding this {@link Mutator} if no neighbor is better.
* An optimality of 1 means that no neighbor is better, while a value of
* 0 means that there is no information supporting such optimality.
*
* @param mutator
* the {@link Mutator} to evaluate
* @return the degree of optimality of the current {@link Optimizer}
* representative for the given {@link Mutator}
*/
public double getOptimalityWith(Mutator mutator) {
if (!mutator.isApplicableOn(representative)
|| parentPool.getOptimalityCheker() != null
&& parentPool.getOptimalityCheker().isOptimal(
representative)) {
return 1;
} else if (mutator instanceof InformedMutator) {
InformedMutator mut = (InformedMutator) mutator;
Integer counts = neighborCounts.get(mut);
counts = counts == null ? 0 : counts;
if (mut.isNeighboringSizeStrict()) {
return (double) counts / mut.getNeighboringLimit();
} else {
double exp = Math.exp((double) counts
/ mut.getNeighboringLimit());
return exp / (1 + exp) * 2 - 1;
}
} else {
Integer loops = neighborLoops.get(mutator);
if (loops == null || loops == 0) {
return 0;
} else {
return (double) (loops - 1) / loops;
}
}
}
/**
*
* @param challengerGenerator
* the {@link Mutator} used to generate the challenger which
* will compete the representative of this {@link Optimizer}
*/
public void compete(Mutator challengerGenerator) {
Individual challenger = challengerGenerator
.generates(representative);
Competition competition = parentPool.getCompetition();
if (competition == null) {
throw new IllegalStateException(
"No competition operator has been provided.");
} else {
// computation can be done
}
Individual winner = competition.compete(representative, challenger);
logger.info("Competition: " + representative + " VS " + challenger
+ " => winner: " + winner);
winner = winner == null ? representative : winner;
if (challengerGenerator instanceof InformedMutator) {
if (winner.equals(representative)) {
InformedMutator mutator = (InformedMutator) challengerGenerator;
if (!neighborCounts.containsKey(challengerGenerator)) {
neighborCounts.put(mutator, 0);
} else {
neighborCounts.put(mutator,
neighborCounts.get(mutator) + 1);
}
} else {
neighborCounts.clear();
}
} else {
if (winner.equals(representative)) {
if (!neighborReferences.containsKey(challengerGenerator)) {
neighborReferences.put(challengerGenerator, challenger);
neighborLoops.put(challengerGenerator, 0);
} else if (neighborReferences.get(challengerGenerator) == null) {
neighborReferences.put(challengerGenerator, challenger);
} else if (neighborReferences.get(challengerGenerator)
.equals(challenger)) {
neighborLoops.put(challengerGenerator,
neighborLoops.get(challengerGenerator) + 1);
neighborReferences.put(challengerGenerator, null);
} else {
// not a reference neighbor to consider
}
} else {
neighborReferences.clear();
neighborLoops.clear();
}
}
representative = winner;
}
/**
*
* @return the best {@link Individual} identified by this
* {@link Optimizer}
*/
public Individual getRepresentative() {
return representative;
}
/**
* Clear all the statistics as if this {@link Optimizer} has just been
* created.
*/
public void reset() {
neighborReferences.clear();
neighborLoops.clear();
neighborCounts.clear();
}
@Override
public String toString() {
String sep = ", ";
String opt = "";
for (Mutator mutator : neighborReferences.keySet()) {
opt += sep + mutator + "=" + getOptimalityWith(mutator);
}
return representative
+ (opt.isEmpty() ? "" : " (" + opt.substring(sep.length())
+ ")");
}
}
/**
* A {@link Competition} aims at selecting a winner among two
* {@link Competitor}s.
*
* @author Matthieu Vergne
*
* @param
*/
public static interface Competition {
/**
*
* @param competitor1
* a first {@link Competitor}
* @param competitor2
* a second {@link Competitor}
* @return the winner of the {@link Competition}, null
if
* there is no winner
*/
public Competitor compete(Competitor competitor1, Competitor competitor2);
}
/**
* An {@link OptimalityChecker} allows to assess the optimality of an
* {@link Individual}.
*
* @author Matthieu Vergne
*
* @param
*/
public static interface OptimalityChecker {
/**
*
* @return true
if the {@link Individual} is ensured to be
* an optimum (global or local), false
otherwise
*/
public boolean isOptimal(Individual individual);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy