/**
*
*/
package vroom.common.heuristics.vrp;
import java.util.LinkedList;
import vroom.common.heuristics.ConstraintHandler;
import vroom.common.heuristics.GenericNeighborhood;
import vroom.common.heuristics.vrp.constraints.FixedNodesConstraint;
import vroom.common.modeling.dataModel.INodeVisit;
import vroom.common.modeling.dataModel.IRoute;
import vroom.common.modeling.dataModel.IVRPSolution;
import vroom.common.modeling.dataModel.Vehicle;
import vroom.common.modeling.util.CostCalculationDelegate;
import vroom.common.utilities.optimization.IConstraint;
import vroom.common.utilities.optimization.IMove;
import vroom.common.utilities.optimization.IParameters;
/**
* <code>SwapNeighborhood</code>
* <p>
* Creation date: Jul 2, 2010 - 11:05:07 AM
*
* @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 SwapNeighborhood<S extends IVRPSolution<?>> extends GenericNeighborhood<S, SwapMove> {
/**
* Creates a new <code>SwapNeighborhood</code>
*
* @param constraintHandler
*/
public SwapNeighborhood(ConstraintHandler<S> constraintHandler) {
super(constraintHandler);
boolean add = true;
for (IConstraint<?> ctr : getConstraintHandler()) {
if (ctr instanceof FixedNodesConstraint<?>) {
add = false;
break;
}
}
if (add) {
getConstraintHandler().addConstraint(new FixedNodesConstraint<S>());
}
}
/**
* Creates a new <code>SwapNeighborhood</code>
*/
public SwapNeighborhood() {
}
/*
* (non-Javadoc)
*
* @see vroom.common.heuristics.GenericNeighborhood#
* deterministicFirstImprovementExploration
* (vroom.common.utilities.optimization.ISolution,
* vroom.common.utilities.optimization.IParameters)
*/
@Override
public SwapMove deterministicFirstImprovement(S solution, IParameters params) {
SwapMove move;
// Iterate over all routes
for (int rI = 0; rI < solution.getRouteCount(); rI++) {
for (int rJ = rI; rJ < solution.getRouteCount(); rJ++) {
// Iterate over all nodes of the first route
for (int i = 0; i < solution.getRoute(rI).length(); i++) {
// Iterate over the nodes of the second route
for (int j = rI == rJ ? i + 1 : 0; j < solution.getRoute(rJ).length(); j++) {
move = new SwapMove(Double.NEGATIVE_INFINITY, solution, rI, rJ, i, j);
evaluateCandidateMove(move);
if ((getAcceptanceCriterion(params).accept(solution, this, move) || params
.acceptNonImproving())
&& getConstraintHandler().isFeasible(solution, move)) {
return move;
}
}
}
}
}
return null;
}
/*
* (non-Javadoc)
*
* @see
* vroom.common.heuristics.GenericNeighborhood#generateCandidateList(vroom.
* common.utilities.optimization.ISolution,
* vroom.common.utilities.optimization.IParameters)
*/
@Override
protected LinkedList<SwapMove> generateCandidateList(S solution, IParameters params) {
LinkedList<SwapMove> candidates = new LinkedList<SwapMove>();
// Iterate over all routes
for (int rI = 0; rI < solution.getRouteCount(); rI++) {
for (int rJ = rI; rJ < solution.getRouteCount(); rJ++) {
// Iterate over all nodes of the first route
for (int i = 0; i < solution.getRoute(rI).length(); i++) {
// Iterate over the nodes of the second route
for (int j = rI == rJ ? i + 1 : 0; j < solution.getRoute(rJ).length(); j++) {
candidates.add(new SwapMove(Double.NEGATIVE_INFINITY, solution, rI, rJ, i,
j));
}
}
}
}
return candidates;
}
/**
* Evaluate the cost-distance improvement for a given move
*
* @param move
* @return the cost-distance improvement for a given move
*/
@Override
protected double evaluateCandidateMove(SwapMove move) {
/* The resulting improvement (= minus cost) */
double improv = 0;
CostCalculationDelegate costHelper = move.mSolution.getParentInstance().getCostDelegate();
IRoute<?> rI = move.mSolution.getRoute(move.getRouteI());
IRoute<?> rJ = move.mSolution.getRoute(move.getRouteJ());
Vehicle vI = rI.getVehicle();
Vehicle vJ = rJ.getVehicle();
INodeVisit nI = rI.getNodeAt(move.getI());
INodeVisit nJ = rJ.getNodeAt(move.getJ());
/* <code>true</code> if successive nodes */
boolean succ = Math.abs(move.getI() - move.getJ()) == 1
&& move.getRouteI() == move.getRouteJ();
if (move.getI() > 0) {
improv -= -costHelper.getCost( // Remove (nodeI-1,nodeI) in routeI
rI.getNodeAt(move.getI() - 1), nI, vI) + costHelper.getCost( // Add
// (nodeI-1,nodeJ)
// in
// routeI
rI.getNodeAt(move.getI() - 1), nJ, vI);
}
if (move.getJ() > 0 && !succ) {
improv -= -costHelper.getCost( // Remove (nodeJ-1,nodeJ) in routeJ #
rJ.getNodeAt(move.getJ() - 1), nJ, vJ) + costHelper.getCost( // Add
// (nodeJ-1,nodeI)
// in
// routeJ
// #
rJ.getNodeAt(move.getJ() - 1), nI, vJ);
}
if (move.getI() < rI.length() - 1 && !succ) {
improv -= -costHelper.getCost( // Remove (nodeI,nodeI+1) in routeI #
nI, rI.getNodeAt(move.getI() + 1), vI) + costHelper.getCost( // Add
// (nodeJ,nodeI+1)
// in
// routeI
// #
nJ, rI.getNodeAt(move.getI() + 1), vI);
}
if (move.getJ() < rJ.length() - 1) {
improv -= -costHelper.getCost( // Remove (nodeJ,nodeJ+1) in routeJ
nJ, rJ.getNodeAt(move.getJ() + 1), vJ) + costHelper.getCost( // Add
// (nodeI,nodeJ+1)
// in
// routeJ
nI, rJ.getNodeAt(move.getJ() + 1), vJ);
}
move.setImprovement(improv);
return improv;
}
/*
* (non-Javadoc)
*
* @see
* vroom.common.heuristics.INeighborhood#executeMove(vroom.common.utilities
* .optimization.ISolution, vroom.common.heuristics.Move)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected boolean executeMoveImplem(S solution, IMove move) {
if (!(move instanceof SwapMove)) {
throw new IllegalArgumentException("The move must be of type SwapMove");
}
int i = ((SwapMove) move).getI();
int j = ((SwapMove) move).getJ();
IRoute rI = solution.getRoute(((SwapMove) move).getRouteI());
IRoute rJ = solution.getRoute(((SwapMove) move).getRouteJ());
// Auxiliary method to solve type safety problems
return executeMove(solution, i, j, rI, rJ);
}
/**
* Auxiliary method for type safety
*
* @param <V>
* @param mSolution
* @param nodeI
* @param nodeJ
* @param rI
* @param rJ
* @return
*/
protected <V extends INodeVisit> boolean executeMove(S solution, int i, int j, IRoute<V> rI,
IRoute<V> rJ) {
if (i != j || rI != rJ) {
rJ.setNodeAt(j, rI.setNodeAt(i, rJ.getNodeAt(j)));
return true;
} else {
return false;
}
}
@Override
public String getShortName() {
return "swap";
}
}