/*
* jCW : a java library for the development of saving based heuristics
*/
package vroom.common.heuristics.cw.algorithms;
import java.util.List;
import vroom.common.heuristics.cw.CWLogging;
import vroom.common.heuristics.cw.IJCWArc;
import vroom.common.heuristics.cw.kernel.ClarkeAndWrightHeuristic;
import vroom.common.modeling.dataModel.INodeVisit;
import vroom.common.modeling.dataModel.IRoute;
import vroom.common.modeling.dataModel.IVRPSolution;
/**
* <code>BasicSavingsHeuristic</code> is a simple implementation of a saving heuristic that considers the candidate
* mergings in a sequential order.
* <p>
* Creation date: Jun 24, 2010 - 2:56:04 PM
*
* @author Jorge E. Mendoza, <a href="http://www.uco.fr">Universite Catholique de l'Ouest</a>
* @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 BasicSavingsHeuristic<S extends IVRPSolution<?>> extends SavingsAlgorithmBase<S> {
/**
* Creates a new <code>BasicSavingsHeuristic</code>.
*
* @param parentHeuristic
* the parent heuristic of this instance from which instance getVrpInstance() and parameters will be read
* @see SavingsAlgorithmBase#SavingsAlgorithmBase(ClarkeAndWrightHeuristic)
*/
public BasicSavingsHeuristic(ClarkeAndWrightHeuristic<S> parentHeuristic) {
super(parentHeuristic);
}
@Override
@SuppressWarnings("unchecked")
public void runHeuristic() {
CWLogging.getAlgoLogger().info("BasicSavingsHeuristic.run: Execution started");
getTimer().restart();
CWLogging.getAlgoLogger().debug("BasicSavingsHeuristic.run: Initialization started");
mNodes.clear();
mNodes.addAll(getInstance().getNodeVisits());
getSolution().clear();
// Create a round trip route for each node
for (INodeVisit node : mNodes) {
IRoute<INodeVisit> currentRoute = (IRoute<INodeVisit>) getParentHeuristic()
.getSolutionFactory().newRoute(getSolution(),
getInstance().getFleet().getVehicle());
currentRoute.appendNode(getInstance().getDepotsVisits().iterator().next());
currentRoute.appendNode(node);
setExterior(node);
assignNodeToRoute(node, currentRoute);
currentRoute.appendNode(getInstance().getDepotsVisits().iterator().next());
((IVRPSolution<IRoute<?>>) getSolution()).addRoute(currentRoute);
}
// Calculate the savings
List<IJCWArc> savingsQueue = calculateSavings(getInstance().getArcs());
// CWLogging.getAlgoLogger().info("savingsQueue: " + savingsQueue);
CWLogging.getAlgoLogger().debug("BasicSavingsHeuristic.run: Route merging");
// Heuristic
for (IJCWArc arc : savingsQueue) {
INodeVisit tail = arc.getTailNode();
INodeVisit head = arc.getHeadNode();
IRoute<INodeVisit> tailRoute = (IRoute<INodeVisit>) getContainingRoute(tail);
IRoute<INodeVisit> headRoute = (IRoute<INodeVisit>) getContainingRoute(head);
// if (CWLogging.getAlgoLogger().isEnabledFor(LoggerHelper.LEVEL_LOW_DEBUG)) {
CWLogging.getAlgoLogger().lowDebug("\t Current Solution %s", getSolution());
// }
CWLogging.getAlgoLogger().lowDebug("\t Largest saving available %s", arc);
// Check the feasibility
if (checkFeasibility(arc, tailRoute, headRoute)) {
// Merge routes
mergeRoutes(arc, tailRoute, headRoute);
CWLogging.getAlgoLogger().lowDebug("\t \t > Routes merged");
} else {
// if (CWLogging.getAlgoLogger().isEnabledFor(LoggerHelper.LEVEL_LOW_DEBUG)) {
// String explanation = getInfeasExpl(arc, tailRoute, headRoute);
// CWLogging.getAlgoLogger().lowDebug("\t \t > Infeasible: %s", explanation);
// }
}
if (getSolution().getRouteCount() == 1)
break;
}
// if(getSolution().getRouteCount()>getParentHeuristic().getInstance().getFleet().size()){
// repairSolutionForLimitedFleet();
// }
getTimer().stop();
CWLogging.getAlgoLogger().info(
"BasicSavingsHeuristic.run: Execution finished, total time %s, solution: %s",
getTimer().readTimeMS(), getSolution());
}
/*
* (non-Javadoc)
*
* @see vroom.common.heuristics.jcw.kernel.IJCWSavingsAlgorithm#
* generateConstraintsReport()
*/
@Override
public String generateConstraintsReport() {
return "NA";
}
}