package com.niacin.metaheuristic.hillclimbing;
import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.niacin.input.Solution;
import com.niacin.metaheuristic.FitnessComparator;
import com.niacin.metaheuristic.Metaheuristic;
import com.niacin.metaheuristic.SimpleFitnessComparator;
import com.niacin.persistence.Bag;
import com.niacin.persistence.HCBag;
import com.niacin.persistence.Persistence;
import com.niacin.problem.Problem;
public class HillClimbing implements Metaheuristic
{
private Log log = LogFactory.getLog(HillClimbing.class);
String name;
int state;
int remainingEvaluations;
Solution currentSolution;
Solution bestSoFarSolution;
ArrayList<Solution> neighbours;
int neighbourPos;
Solution nextSolution = null;
@Override
public Solution getNextInput(Problem problem)
{
HCBag bag = (HCBag) Persistence.load(problem.name(), HCBag.class);
if (bag == null)
state = HillClimbing.START;
else
unpack(bag);
if (bag != null && bag.getRemainingEvaluations() == 0)
{
log.info("NO BUDGET: bailing out with the best so far solution");
nextSolution = bag.getBestSoFarSolution();
return nextSolution;
}
switch (state)
{
case START :
log.info("START");
name = problem.name();
remainingEvaluations = problem.getRemainingTrials();
currentSolution = problem.initialSolution();
bestSoFarSolution = currentSolution;
nextSolution = currentSolution;
neighbours = new ArrayList<Solution>();
neighbourPos = 0;
state = HillClimbing.GENERATE_NEIGHBOURS;
break;
case MOVE :
{
log.info("CLIMB");
double bestImprovement = 0;
boolean moved = false;
FitnessComparator comparator = new SimpleFitnessComparator();
for (Solution neighbour : neighbours)
{
double improvement = comparator.compare(problem, neighbour, currentSolution);
if (improvement > bestImprovement)
{
currentSolution = neighbour;
nextSolution = neighbour;
bestImprovement = improvement;
moved = true;
if (comparator.compare(problem, neighbour, bag.getBestSoFarSolution()) > 0)
{
log.info("UPDATING BEST SO FAR. FITNESS:" + neighbour.getFitness());
bestSoFarSolution = neighbour;
}
}
}
if (!moved && bag.getRemainingEvaluations() > 0)
{
log.info("RANDOM RESTART");
currentSolution = problem.generateRandomRestart();
nextSolution = currentSolution;
state = HillClimbing.GENERATE_NEIGHBOURS;
break;
}
}
case GENERATE_NEIGHBOURS :
log.info("GENERATE NEIGHBOURS");
neighbours = NeighbourhoodGenerator.generateNeighbours(currentSolution);
neighbourPos = 0;
state = EVALUATE_NEIGHBOURS;
case EVALUATE_NEIGHBOURS :
{
log.info("EVALUATE " + (neighbourPos + 1) + "/" + neighbours.size() + "th NEIGHBOUR");
//find next neighbour without fitness evaluation
nextSolution = neighbours.get(neighbourPos);
if (neighbourPos == neighbours.size() - 1)
{
state = HillClimbing.MOVE;
}
else
neighbourPos++;
break;
}
}
remainingEvaluations--;
return nextSolution;
}
@Override
public void recordFitness(Problem problem, double fitness)
{
nextSolution.setFitness(fitness);
Persistence.store(pack(problem));
}
public static final int START = 0;
public static final int MOVE = 1;
public static final int GENERATE_NEIGHBOURS = 2;
public static final int RANDOM_RESTART = 4;
public static final int EVALUATE_NEIGHBOURS = 3;
@Override
public Bag pack(Problem problem)
{
HCBag bag = new HCBag();
bag.setName(problem.name());
bag.setState(state);
bag.setRemainingEvaluations(remainingEvaluations);
bag.setBestSoFarSolution(bestSoFarSolution);
bag.setCurrentSolution(currentSolution);
bag.setNeighbours(new ArrayList<Solution>(neighbours));
bag.setNeighbourPos(neighbourPos);
return bag;
}
@Override
public void unpack(Bag bag)
{
HCBag hb = (HCBag) bag;
name = hb.getName();
state = hb.getState();
remainingEvaluations = hb.getRemainingEvaluations();
currentSolution = hb.getCurrentSolution();
bestSoFarSolution = hb.getBestSoFarSolution();
neighbours = new ArrayList<Solution>(hb.getNeighbours());
neighbourPos = hb.getNeighbourPos();
}
}