/*
* 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.hyperheuristics;
import hh.creditassigment.Credit;
import hh.creditassigment.CreditFunctionInputType;
import hh.creditassigment.ICreditAssignment;
import hh.creditassignment.offspringparent.AbstractOffspringParent;
import hh.creditassignment.offspringpopulation.AbstractOffspringPopulation;
import hh.creditassignment.populationcontribution.AbstractPopulationContribution;
import hh.history.CreditHistory;
import hh.history.OperatorQualityHistory;
import hh.history.OperatorSelectionHistory;
import hh.moea.SteadyStateNSGAII;
import hh.nextheuristic.INextHeuristic;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.moeaframework.core.EpsilonBoxDominanceArchive;
import org.moeaframework.core.Initialization;
import org.moeaframework.core.NondominatedSortingPopulation;
import org.moeaframework.core.ParallelPRNG;
import org.moeaframework.core.Population;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Selection;
import org.moeaframework.core.Solution;
import org.moeaframework.core.Variation;
/**
* This hyperheuristic is uses steady state NSGAII. Every iteration a new
* operator is selected
*
* @author SEAK2
*/
public class AOSSSNSGAII extends SteadyStateNSGAII implements IHyperHeuristic {
/**
* The type of heuristic selection method
*/
private final INextHeuristic operatorSelector;
/**
* The Credit definition to be used that defines how much credit to receive
* for certain types of solutions
*/
private final ICreditAssignment creditDef;
/**
* The history that stores all the heuristics selected by the hyper
* heuristics. History can be extracted by getSelectionHistory(). Used for
* analyzing the results to see the dynamics of heuristics selected
*/
private OperatorSelectionHistory operatorSelectionHistory;
/**
* The history that stores all the rewards received by the operators. Used
* for analyzing the results to see the dynamics in rewards
*/
private CreditHistory creditHistory;
/**
* The set of heuristics that the hyper heuristic is able to work with
*/
private final Collection<Variation> heuristics;
/**
* The selection operator.
*/
private final Selection selection;
/**
* The history of the heuristics' qualities over time. Used for analyzing
* the results to see the dynamics of the heuristic qualities
*/
private OperatorQualityHistory qualityHistory;
/**
* parallel purpose random generator
*/
private final ParallelPRNG pprng;
/**
* Name to id the hyper-heuristic
*/
private String name;
/**
* A temporary list to store solutions that are removed for the population
* in order to correctly update the Pareto front indices
*/
private ArrayList<Integer> removedSolutions;
public AOSSSNSGAII(Problem problem, NondominatedSortingPopulation population,
EpsilonBoxDominanceArchive archive, Selection selection,
Initialization initialization, INextHeuristic heuristicSelector,
ICreditAssignment creditDef) {
super(problem, population, archive, selection, null, initialization);
this.heuristics = heuristicSelector.getOperators();
this.selection = selection;
this.operatorSelector = heuristicSelector;
this.creditDef = creditDef;
this.operatorSelectionHistory = new OperatorSelectionHistory(heuristics);
this.qualityHistory = new OperatorQualityHistory(heuristics);
this.creditHistory = new CreditHistory(heuristics);
this.pprng = new ParallelPRNG();
this.removedSolutions = new ArrayList<>();
//Initialize the stored pareto front
super.initialize();
}
@Override
public void iterate() {
//select next heuristic
Variation operator = operatorSelector.nextHeuristic();
operatorSelectionHistory.add(operator, this.numberOfEvaluations);
//create new offspring
Solution[] parents = selection.select(operator.getArity(), population);
Solution[] children = operator.evolve(parents);
if (creditDef.getInputType() == CreditFunctionInputType.OP) {
double creditValue = 0.0;
for (Solution child : children) {
Solution refParent = parents[pprng.nextInt(parents.length)];
evaluate(child);
enlu.addSolution(child, population);
//credit definitions operating on population and archive does
//NOT modify the population by adding the child to the population/archive
switch (creditDef.getOperatesOn()) {
case PARENT:
creditValue += ((AbstractOffspringParent) creditDef).compute(child, refParent, population, null);
break;
default:
throw new NullPointerException("Credit definition not "
+ "recognized. Used " + creditDef.getInputType() + ".");
}
int worstIndex = findWorstSolution();
population.remove(worstIndex);
}
Credit reward = new Credit(this.numberOfEvaluations, creditValue);
operatorSelector.update(reward, operator);
creditHistory.add(operator, reward);
} else if (creditDef.getInputType() == CreditFunctionInputType.SI) {
try {
double creditValue = 0.0;
for (Solution child : children) {
removedSolutions.clear();
evaluate(child);
enlu.addSolution(child, population);
int worstIndex = findWorstSolution();
removedSolutions.add(worstIndex);
population.remove(worstIndex);
if (worstIndex != population.size()) { //solution made it in population
//credit definitions operating on PF and archive will
//modify the nondominated population by adding the child to the nondominated population.
switch (creditDef.getOperatesOn()) {
case PARETOFRONT:
creditValue += ((AbstractOffspringPopulation) creditDef).compute(child, null);
break;
default:
throw new NullPointerException("Credit definition not "
+ "recognized. Used " + creditDef.getInputType() + ".");
}
}
}
Credit reward = new Credit(this.numberOfEvaluations, creditValue);
operatorSelector.update(reward, operator);
creditHistory.add(operator, reward);
} catch (Exception e) {
Logger.getLogger(AOSSSNSGAII.class.getName()).log(Level.SEVERE, null, e);
}
} else if (creditDef.getInputType() == CreditFunctionInputType.CS) {
for (Solution child : children) {
removedSolutions.clear();
evaluate(child);
child.setAttribute("heuristic", new SerializableVal(operator.toString()));
enlu.addSolution(child, population);
int worstIndex = findWorstSolution();
removedSolutions.add(worstIndex); //only need to keep track of the latest removal
population.remove(worstIndex);
}
HashMap<Variation, Credit> popContRewards;
switch (creditDef.getOperatesOn()) {
case PARETOFRONT:
popContRewards = ((AbstractPopulationContribution) creditDef).
compute(getParetoFront(), heuristics, this.numberOfEvaluations);
break;
default:
throw new NullPointerException("Credit definition not "
+ "recognized. Used " + creditDef.getInputType() + ".");
}
Iterator<Variation> iter = popContRewards.keySet().iterator();
while (iter.hasNext()) {
Variation operator_i = iter.next();
operatorSelector.update(popContRewards.get(operator_i), operator_i);
creditHistory.add(operator_i, new Credit(this.numberOfEvaluations, popContRewards.get(operator_i).getValue()));
}
} else {
throw new UnsupportedOperationException("RewardDefinitionType not recognized ");
}
// updateQualityHistory();
}
/**
* Finds the Pareto front using the Pareto rank from the efficient
* nondomination update level method
*
* @return
*/
private Population getParetoFront() {
Population paretoFront = new Population();
ArrayList<Integer> pfIndices = new ArrayList(enlu.getParetoFront());
HashMap<Integer, Integer> map = new HashMap(); //key is old index, value is new index
for (Integer index : pfIndices) {
map.put(index, index);
}
for(Integer removedIndex : removedSolutions){
map.remove(removedIndex);
}
//for every index that has been removed, update any Pareto front indices that are larger than it
//do not include any index belonging to both the Pareto front and the removed list (this can occur if the Pareto front is the only front)
Iterator<Integer> iter = map.keySet().iterator();
while (iter.hasNext()) {
int pfIndex = iter.next();
for (Integer removedIndex : removedSolutions) {
if (pfIndex > removedIndex) {
map.put(pfIndex, map.get(pfIndex) - 1);
}
}
}
for (Integer index : map.values()) {
if(index<0){
System.err.println("");
}
paretoFront.add(population.get(index));
}
return paretoFront;
}
/**
* Returns the ordered history of operators that were selected
*
* @return The ordered history of operators that were selected
*/
@Override
public OperatorSelectionHistory getSelectionHistory() {
return operatorSelectionHistory;
}
/**
* gets the quality history stored for each operator in the hyper-heuristic
*
* @return
*/
@Override
public OperatorQualityHistory getQualityHistory() {
return qualityHistory;
}
/**
* gets the credit history stored for each operator in the hyper-heuristic
*
* @return
*/
@Override
public CreditHistory getCreditHistory() {
return creditHistory;
}
/**
* Reset the hyperheuristic. Clear all selection history and the credit
* repository. Clears the population and the archive
*/
@Override
public void reset() {
operatorSelectionHistory.reset();
operatorSelector.reset();
numberOfEvaluations = 0;
qualityHistory.clear();
population.clear();
archive.clear();
creditDef.clear();
}
@Override
public ICreditAssignment getCreditDefinition() {
return creditDef;
}
@Override
public INextHeuristic getNextHeuristicSupplier() {
return operatorSelector;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}