/* * */ package vroom.optimization.online.jmsa.vrp.vrpsd; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import umontreal.iro.lecuyer.probdist.Distribution; import vroom.common.modeling.dataModel.INodeVisit; import vroom.common.modeling.dataModel.attributes.IStochasticDemand; import vroom.common.modeling.dataModel.attributes.RequestAttributeKey; import vroom.optimization.online.jmsa.DistinguishedSolutionBase; import vroom.optimization.online.jmsa.IActualRequest; import vroom.optimization.online.jmsa.IDistinguishedSolution; import vroom.optimization.online.jmsa.components.ComponentManager; import vroom.optimization.online.jmsa.components.ISolutionBuilderParam; import vroom.optimization.online.jmsa.components.RegretSolutionBuilderBase; import vroom.optimization.online.jmsa.vrp.MSAVRPInstance; import vroom.optimization.online.jmsa.vrp.VRPRequest; import vroom.optimization.online.jmsa.vrp.VRPActualRequest; import vroom.optimization.online.jmsa.vrp.VRPScenario; import vroom.optimization.online.jmsa.vrp.VRPScenarioRoute; /** * The Class <code>VRPSimpleRegret</code> is an implementation of the regret algorithm as proposed in Van Hentenryck and Bent (Online Stochastic * Combinatorial Optimization, 2006). * <p> * For each pending requests <code>r</code> it calculates the sum of the <code>f(r,s)</code> over all the scenarios <code>s</code>, where * <code>f(r,s)</code> is equal to <code>0</code> if there exists a feasible insertion/swap allowing the request <code>r</code> to be served first in * scenario <code>r</code>. * </p> * <p> * This implementation is for the single vehicle dynamic VRPSD * </p> * <p> * Creation date: Aug 24, 2010 - 11:43:29 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 VRPSDSimpleRegret extends RegretSolutionBuilderBase<VRPScenario> { private double mInsertionCostUB; public VRPSDSimpleRegret(ComponentManager<VRPScenario, ?> componentManager) { super(componentManager); double maxCost1 = 0, maxCost2 = 0, minCost = Double.POSITIVE_INFINITY; Set<INodeVisit> reqs = getInstance().getNodeVisits(); reqs.addAll(getInstance().getDepotsVisits()); boolean s = getInstance().isSymmetric(); if (s) { Iterator<INodeVisit> it = reqs.iterator(); while (!reqs.isEmpty()) { INodeVisit i = it.next(); it.remove(); for (INodeVisit j : reqs) { double c = getInstance().getCost(i, j, getInstance().getFleet().getVehicle()); if (c > maxCost1) { maxCost2 = maxCost1; maxCost1 = c; } else if (c > maxCost2) { maxCost2 = c; } if (c < minCost) { minCost = c; } } } mInsertionCostUB = maxCost1 + maxCost2 - minCost; } else { throw new UnsupportedOperationException("Asymmetric instances are not supported"); } } @Override protected Collection<? extends IActualRequest> selectCandidateRequests() { Iterable<? extends IActualRequest> reqs = getComponentManager().getParentMSAProxy() .getInstance() .getPendingRequests(); LinkedList<VRPActualRequest> candidates = new LinkedList<VRPActualRequest>(); Set<INodeVisit> depotsSet = getInstance().getDepotsVisits(); LinkedList<VRPActualRequest> depots = new LinkedList<VRPActualRequest>(); for (INodeVisit d : depotsSet) { depots.add(new VRPActualRequest(d)); } double cap = getInstance().getFleet().getVehicle().getCapacity() - getInstance().getCurrentLoad(0, 0); if (cap <= 0) { return depots; } for (IActualRequest r : reqs) { VRPActualRequest ar = (VRPActualRequest) r; Distribution dist = ((IStochasticDemand) ar.getParentRequest().getAttribute( RequestAttributeKey.DEMAND)).getDistribution(0); if (dist.cdf(cap) > 0.9) { candidates.add(ar); } } return candidates.isEmpty() ? depots : candidates; } protected MSAVRPInstance getInstance() { return (MSAVRPInstance) getComponentManager().getParentMSAProxy().getInstance(); } @Override protected IDistinguishedSolution defaultDecision(ISolutionBuilderParam param) { return new DistinguishedSolutionBase(new VRPActualRequest(getInstance().getDepotsVisits() .iterator() .next())); } @Override protected double evaluateRegret(IActualRequest request, VRPScenario s, double currentValue) { // Ignore empty scenarios if (s.getRouteCount() <= 0) { return currentValue; } VRPScenarioRoute currentRoute = s.getRoute(0); VRPActualRequest req = (VRPActualRequest) request; VRPActualRequest firstReq = currentRoute.getFirstActualRequest(); if (firstReq == null || req == null) { return currentValue; } double regret = 0; double cap = getInstance().getFleet().getVehicle().getCapacity() - getInstance().getCurrentLoad(0, 0); // r is already the first request if (firstReq.getID() == request.getID()) { regret = 0; } // r can be visited in the route without violating the // vehicle capacity, regret is the normalized insertion cost else if (req.getDemand() <= cap) { regret = getInstance().getCostDelegate().getInsertionCost(req, getInstance().getShrunkRequest(0), firstReq, getInstance().getFleet().getVehicle()) / mInsertionCostUB; } else { cap -= req.getDemand(); for (VRPRequest r : currentRoute.getNodeSequence()) { if (cap + r.getDemand() >= 0) { // r can be visited in the route if one request is removed // regret is the normalized insertion cost + 1 regret = getInstance().getCostDelegate().getInsertionCost(req, getInstance().getShrunkRequest(0), firstReq, getInstance().getFleet().getVehicle()) / mInsertionCostUB + 1; break; } } // r cannot be visited in the route if only one request can be removed // there is no guarantee that r can be served in the route if (regret == 0) { regret = 2; } } return currentValue + regret; } }