/** * */ package vroom.trsp.datamodel.costDelegates; import java.util.List; import java.util.ListIterator; import vroom.common.utilities.optimization.IMove; import vroom.trsp.datamodel.ITRSPTour; import vroom.trsp.datamodel.ITourIterator; import vroom.trsp.datamodel.TRSPInstance; import vroom.trsp.datamodel.TRSPTour; import vroom.trsp.datamodel.TRSPTour.TRSPTourIterator; import vroom.trsp.datamodel.Technician; import vroom.trsp.optimization.InsertionMove; import vroom.trsp.optimization.localSearch.TRSPShift.TRSPShiftMove; /** * <code>TRSPTWViolationDelegate</code> is an implementation of {@link TRSPCostDelegate} that evaluates the time window * violations (i.e. the lateness at each node). * <p> * Creation date: Mar 24, 2011 - 5:20:20 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 TRSPTWViolationDelegate extends TRSPCostDelegate { /** the max flag **/ private boolean mMaxValue; /** * Getter for the max flag: <code>true</code> if only the maximum TW violation is recorded, <code>false</code> if * its the sum of TW violations * * @return the value of the maxValue flag */ public boolean isMaxValue() { return this.mMaxValue; } /** * Setter for the max flag<code>true</code> if only the maximum TW violation is recorded, <code>false</code> if its * the sum of TW violations * * @param maxValue * the value to be set for the max flag */ public void setMaxValue(boolean maxValue) { this.mMaxValue = maxValue; } /** * Creates a new <code>TRSPTWViolationDelegate</code> */ public TRSPTWViolationDelegate(boolean maxValue) { super(); this.mMaxValue = maxValue; } @Override protected double evaluateTRSPTour(TRSPTour tour, int node, boolean updateTour) { if (updateTour && !tour.isAutoUpdated()) throw new IllegalStateException( "The tour must have its autoupdate flag set to true for proper working"); // Cumulated working time double cost = node != ITRSPTour.UNDEFINED ? tour.getCumulatedCost(node) : 0; // Iterator over the tour TRSPTourIterator it = node != ITRSPTour.UNDEFINED ? tour.iterator(node) : tour.iterator(); if (!it.hasNext()) { if (updateTour) tour.setTotalCost(cost); return cost; } // First node while (it.hasNext()) { node = it.next(); double tmp = tour.getInstance().isDepot(node) ? 0 : tour.getLateness(node); cost = isMaxValue() ? Math.max(tmp, cost) : cost + tmp; // Set the cumulated cost if (updateTour) { tour.setTotalCost(cost); tour.setCumulatedCost(node, cost); } } // Set the total cost if (updateTour) tour.setTotalCost(cost); return cost; } @Override protected double evaluateGenericTour(ITRSPTour tour) { double cost = 0; if (tour.length() == 0) return 0; TRSPInstance ins = tour.getInstance(); Technician tech = ins.getTechnician(tour.getTechnicianId()); // Cumulated working time double time = 0; // Iterator over the tour ITourIterator it = tour.iterator(); // First node int pred = it.next(); while (it.hasNext()) { int node = it.next(); // If time windows are enforced the vehicle has to wait until TW start time = ins.getTimeWindow(pred).getEarliestStartOfService(time); // Add the service time of predecessor time += ins.getServiceTime(pred); // Add the travel time time += ins.getCostDelegate().getTravelTime(pred, node, tech); pred = node; double tmp = ins.getTimeWindow(node).getViolation(time); cost = isMaxValue() ? Math.max(tmp, cost) : cost + tmp; } // If time windows are enforced the vehicle has to wait at the last depot until TW start time = ins.getTimeWindow(pred).getEarliestStartOfService(time); // Add the service time of the last node time += ins.getServiceTime(pred); return cost; } @Override public double getInsertionCost(TRSPTour route, int predecessor, List<Integer> insertedTour, int successor) { throw new UnsupportedOperationException("This method is not implemented yet"); } @Override public double getInsertionCost(TRSPTour tour, int predecessor, int node, int successor) { if (!tour.isAutoUpdated()) throw new IllegalStateException( "The tour must have its autoupdate flag set to true for proper working"); double cost = 0; double arrivalTime; if (predecessor != ITRSPTour.UNDEFINED) { // Evaluate arrival time at node arrivalTime = tour.getEarliestDepartureTime(predecessor) + tour.getTravelTime(predecessor, node); cost = tour.getLateness(predecessor); } else // Node is the first node of the tour arrivalTime = tour.getEarliestStartTime(); // The lateness at this node double lateness = tour.getInstance().isDepot(node) ? 0 : tour.getTimeWindow(node) .getViolation(arrivalTime); cost = isMaxValue() ? Math.max(cost, lateness) : cost + lateness; // Propagate to following nodes int pred = node; if (successor != ITRSPTour.UNDEFINED) { TRSPTourIterator it = tour.iterator(successor); while (it.hasNext()) { node = it.next(); // Evaluate arrival time at node arrivalTime = tour.getTimeWindow(pred).getEarliestStartOfService(arrivalTime) + tour.getServiceTime(pred) + tour.getTravelTime(pred, node); // The lateness at this node lateness = tour.getInstance().isDepot(node) ? 0 : tour.getTimeWindow(node) .getViolation(arrivalTime); cost = isMaxValue() ? Math.max(cost, lateness) : cost + lateness; pred = node; } } return cost - tour.getTotalCost(); } @Override protected double evaluateInsMove(InsertionMove move) { // FIXME include the cost of the trip to depot if (move.isDepotTrip()) throw new UnsupportedOperationException(); double improvement = -getInsertionCost(move.getTour(), move.getTour().getPred(move.getInsertionSucc()), move.getRequest().getID(), move.getInsertionSucc()); return improvement; } /** * Specific implementation of {@link #evaluateMove(IMove)} for {@link TRSPShiftMove} * * @param tour * the considered tour * @param move * the move to be evaluated * @return the improvement resulting from the execution of <code>move</code> on <code>tour</code> */ @Override public double evaluateShiftMove(TRSPShiftMove move) { if (!move.getTour().isAutoUpdated()) throw new IllegalStateException( "The tour must have its autoupdate flag set to true for proper working"); // Build the changed sequence List<Integer> changedSequence = move.getChangedSequence(); // The changed sequence predecessor (unchanged) ListIterator<Integer> it = changedSequence.listIterator(); // The last node that is unchanged int lastUnchanged = it.next(); // The evaluation of the tour at the last unchanged node double evaluation = lastUnchanged != ITRSPTour.UNDEFINED ? move.getTour().getCumulatedCost( lastUnchanged) : isMaxValue() ? Double.NEGATIVE_INFINITY : 0; double newEarliestDeparture = lastUnchanged != ITRSPTour.UNDEFINED ? move.getTour() .getEarliestDepartureTime(lastUnchanged) : move.getTour().getEarliestStartTime(); int pred = lastUnchanged; while (it.hasNext()) { int n = it.next(); if (pred != ITRSPTour.UNDEFINED) newEarliestDeparture += move.getTour().getTravelTime(pred, n); // The violation is equal to the difference between the arrival time and the TW end double newViolation = move.getTour().getTimeWindow(n) .getViolation(newEarliestDeparture); newEarliestDeparture = move.getTour().getTimeWindow(n) .getEarliestStartOfService(newEarliestDeparture) + move.getTour().getServiceTime(n); if (isMaxValue()) { if (newViolation > evaluation) { evaluation = newViolation; } } else { evaluation += newViolation; } pred = n; } double improvement = move.getTour().getTotalCost() - evaluation; return improvement; } @Override public boolean isInsertionSeqDependent() { return true; } }