/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package hh.heuristicselectors;
import hh.nextheuristic.AbstractOperatorSelector;
import hh.creditassigment.Credit;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import org.moeaframework.core.Variation;
/**
* Selects heuristics based on probability which is proportional to the
* heuristics credits. Each heuristic gets selected with a minimum probability
* of pmin. If current credits in credit repository becomes negative, zero
* credit is re-assigned to that heuristic. For the first iteration, heuristics
* are selected with uniform probability.
*
* @author nozomihitomi
*/
public class RouletteWheel extends AbstractOperatorSelector {
/**
* Hashmap to store the selection probabilities of each heuristic
*/
protected HashMap<Variation, Double> probabilities;
/**
* The minimum probability for a heuristic to be selected
*/
protected final double pmin;
/**
* Constructor to initialize probability map for selection
*
* @param heuristics from which to select from
* @param pmin The minimum probability for a heuristic to be selected
*/
public RouletteWheel(Collection<Variation> heuristics, double pmin) {
super(heuristics);
this.pmin = pmin;
this.probabilities = new HashMap();
reset();
}
/**
* Will return the next heuristic that gets selected based on probability
* proportional to a heuristics credits. Each heuristic gets selected with a
* minimum probability of pmin
*
* @return
*/
@Override
public Variation nextHeuristic() {
double p = pprng.nextDouble();
Iterator<Variation> iter = probabilities.keySet().iterator();
double sum = 0.0;
Variation heuristic = null;
while (iter.hasNext()) {
heuristic = iter.next();
sum += probabilities.get(heuristic);
if (sum >= p) {
break;
}
}
incrementIterations();
if (heuristic == null) {
throw new NullPointerException("No heuristic was selected by Probability matching heuristic selector. Check probabilities");
} else {
return heuristic;
}
}
/**
* calculate the sum of all qualities across the heuristics
*
* @return the sum of the heuristics' qualities
*/
protected double sumQualities() {
double sum = 0.0;
Iterator<Variation> iter = probabilities.keySet().iterator();
while (iter.hasNext()) {
sum += qualities.get(iter.next());
}
return sum;
}
/**
* Clears the credit repository and resets the selection probabilities
*/
@Override
public final void reset() {
super.resetQualities();
super.reset();
probabilities.clear();
Iterator<Variation> iter = operators.iterator();
while (iter.hasNext()) {
//all heuristics get uniform selection probability at beginning
probabilities.put(iter.next(), 1.0 / (double) operators.size());
}
}
@Override
public String toString() {
return "ProbabilityMatching";
}
/**
* Updates the selection probabilities of the heuristics according to the
* qualities of each heuristic.
*/
protected void updateProbabilities(){
double sum = sumQualities();
// if the credits sum up to zero, apply uniform probabilty to heuristics
Iterator<Variation> iter = operators.iterator();
if (Math.abs(sum) < Math.pow(10.0, -14)) {
while (iter.hasNext()) {
Variation heuristic_i = iter.next();
probabilities.put(heuristic_i, 1.0 / (double) operators.size());
}
} else { //else update probabilities proportional to quality
while (iter.hasNext()) {
Variation heuristic_i = iter.next();
double newProb = pmin + (1 - probabilities.size() * pmin)
* (qualities.get(heuristic_i) / sum);
probabilities.put(heuristic_i, newProb);
}
}
}
/**
* Selection probabilities are updated
* @param reward given to the heuristic
* @param heuristic to be rewarded
*/
@Override
public void update(Credit reward, Variation heuristic) {
qualities.put(heuristic, qualities.get(heuristic)+reward.getValue());
super.checkQuality();
updateProbabilities();
}
}