package vroom.optimization.online.jmsa.vrp.vrpsd;
import vroom.common.heuristics.vls.IVLSAcceptanceCriterion;
import vroom.common.heuristics.vls.IVLSState;
import vroom.common.heuristics.vls.VLSGlobalParameters;
import vroom.common.heuristics.vls.VersatileLocalSearch;
import vroom.common.utilities.optimization.IAcceptanceCriterion;
import vroom.common.utilities.optimization.IInstance;
import vroom.common.utilities.optimization.IMove;
import vroom.common.utilities.optimization.INeighborhood;
import vroom.common.utilities.optimization.ISolution;
import vroom.common.utilities.optimization.OptimizationSense;
import vroom.optimization.online.jmsa.vrp.VRPScenario;
import vroom.optimization.online.jmsa.vrp.VRPScenarioRoute;
/**
* The Class <code>VRPSDAcceptanceCriterion</code> is an implementation of {@link IAcceptanceCriterion} and
* {@link IVLSAcceptanceCriterion} that accepts certain deterioration in the objective function if the new solution has
* a better distribution of load among routes
* <p>
* Creation date: Dec 2, 2010 - 3:17:13 PM.
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public class VRPSDAcceptanceCriterion implements IAcceptanceCriterion, IVLSAcceptanceCriterion {
/** optimization sense **/
private final OptimizationSense mOptimizationSense;
/**
* Getter for optimization sense
*
* @return the optimization sense
*/
public OptimizationSense getOptimizationSense() {
return mOptimizationSense;
}
/** the cost deterioration tolerance **/
private double mCostTolerance = 0.05;
/**
* Getter for the cost deterioration tolerance
*
* @return the value of the cost tolerance
*/
public double getCostTolerance() {
return this.mCostTolerance;
}
/**
* Setter for the cost deterioration tolerance
*
* @param costTolerance
* the value to be set for the cost tolerance
*/
public void setCostTolerance(double costTolerance) {
this.mCostTolerance = costTolerance;
}
/**
* the load increase threshold for the first route above which a deteriorating solution will be accepted (between 0
* an 1)
**/
private double mLoadThreshold = 0.1;
/**
* Getter for the load increase threshold for the first route above which a deteriorating solution will be accepted
* (between 0 an 1)
*
* @return the value of name
*/
public double getLoadThreshold() {
return this.mLoadThreshold;
}
/**
* Setter for the load increase threshold for the first route above which a deteriorating solution will be accepted
* (between 0 an 1)
*
* @param name
* the value to be set for the load increase threshold for the first route above which a deteriorating
* solution will be accepted (between 0 an 1)
*/
public void setLoadThreshold(double name) {
this.mLoadThreshold = name;
}
/**
* Creates a new <code>VRPSDAcceptanceCriterion</code> for a {@link VersatileLocalSearch} procedure
*
* @param params
*/
public VRPSDAcceptanceCriterion(VLSGlobalParameters params) {
mOptimizationSense = params.get(VLSGlobalParameters.OPTIMIZATION_DIRECTION) < 0 ? OptimizationSense.MINIMIZATION
: OptimizationSense.MAXIMIZATION;
}
/**
* Creates a new <code>VRPSDAcceptanceCriterion</code>
*
* @param optimizationSense
*/
public VRPSDAcceptanceCriterion(OptimizationSense optimizationSense) {
mOptimizationSense = optimizationSense;
}
@Override
public boolean acceptSolution(IVLSState<?> state, IInstance instance, ISolution solution) {
return accept(state.getBestSolution(state.getCurrentPhase()), solution);
}
@Override
public void initialize() {
// Do nothing
}
@Override
public void reset() {
// Do nothing
}
@Override
public boolean accept(ISolution oldSolution, ISolution newSolution) {
VRPScenario original = (VRPScenario) oldSolution;
VRPScenario candidate = (VRPScenario) newSolution;
// Cost comparison
if (candidate.getCost() < original.getCost()) {
return true;
}
// Deteriorating solution
else if (candidate.getCost() < (1 + getCostTolerance()) * original.getCost() && candidate.getRouteCount() > 0
&& original.getRouteCount() > 0) {
// First routes
VRPScenarioRoute or = null;
VRPScenarioRoute cand = null;
for (VRPScenarioRoute r : original) {
if (r.containsShrunkNode()) {
or = r;
break;
}
}
for (VRPScenarioRoute r : candidate) {
if (r.containsShrunkNode()) {
cand = r;
break;
}
}
// The candidate has a higher load on first route, which is
// desirable
if (or != null && cand != null
&& (cand.getLoad() - or.getLoad()) > cand.getVehicle().getCapacity() * getLoadThreshold()) {
return true;
} else {
return false;
}
} else {
return false;
}
}
@Override
public boolean accept(ISolution solution, IMove move) {
return accept(solution, null, move);
}
@SuppressWarnings("unchecked")
@Override
public boolean accept(ISolution solution, INeighborhood<?, ?> neighborhood, IMove move) {
// FIXME find a more efficient implementation depending on the move
ISolution clone = solution.clone();
((INeighborhood<ISolution, IMove>) neighborhood).executeMove(clone, move);
return accept(solution, clone);
}
@Override
public double getImprovement(ISolution oldSolution, ISolution newSolution) {
return mOptimizationSense.getImprovement(oldSolution.getObjectiveValue(), newSolution.getObjectiveValue());
}
@Override
public VRPSDAcceptanceCriterion clone() {
VRPSDAcceptanceCriterion clone = new VRPSDAcceptanceCriterion(mOptimizationSense);
clone.mCostTolerance = mCostTolerance;
clone.mLoadThreshold = mLoadThreshold;
return clone;
}
}