/** * */ package vroom.common.instances; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.ListIterator; import umontreal.iro.lecuyer.rng.MRG32k3a; import umontreal.iro.lecuyer.rng.RandomStream; import vroom.common.heuristics.ConstraintHandler; import vroom.common.heuristics.cw.CWParameters; import vroom.common.heuristics.cw.algorithms.RandomizedSavingsHeuristic; import vroom.common.heuristics.cw.kernel.ClarkeAndWrightHeuristic; import vroom.common.heuristics.vrp.constraints.CapacityConstraint; import vroom.common.modeling.dataModel.ListRoute.ArrayListRoute; import vroom.common.modeling.dataModel.INodeVisit; import vroom.common.modeling.dataModel.IVRPInstance; import vroom.common.modeling.dataModel.IVRPRequest; import vroom.common.modeling.dataModel.Solution; import vroom.common.modeling.dataModel.attributes.ITimeWindow; import vroom.common.modeling.io.ChristofidesPersistenceHelper; import vroom.common.modeling.io.FlatFilePersistenceHelper; import vroom.common.utilities.FileBufferedWriter; import vroom.common.utilities.Utilities; import vroom.common.utilities.Utilities.Random; import vroom.common.utilities.dataModel.ObjectWithIdComparator; import vroom.common.utilities.logging.LoggerHelper; import vroom.common.utilities.logging.Logging; import vroom.common.utilities.ssj.RandomSourceBase; /** * The class <code>DVRPReleaseDateGenerator</code> is used to generate a release date file for a given instance of the * VRP * <p> * Creation date: Nov 8, 2011 - 10:30:45 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 DVRPReleaseDateGenerator extends RandomSourceBase { /** * The format string for the release date file, the first argument is the path to the folder, the second the * instance name, and the third the proportion of dynamic requests */ public static String sNameFormat = "%1$s/%2$s_rd_%3$s.txt"; /** * Creates a new <code>DVRPReleaseDateGenerator</code> * * @param stream * the random stream that will be used to generate random numbers */ public DVRPReleaseDateGenerator(RandomStream stream) { super(stream); } /** * Generate a release date file and save it in the specified {@code path} using the format defined in * {@link #sNameFormat} * * @param instance * the static instance * @param dynProp * the proportion of dynamic requests (between 0 an 1) * @param destDir * the destination folder * @throws IOException */ public void generateRDFile(IVRPInstance instance, double dynProp, String destDir) throws IOException { // Get the planning horizon int hStart = 0; int hEnd = 0; ITimeWindow tw = instance.getDepot(0).getTimeWindow(); if (tw != null) { hStart = (int) tw.startAsDouble(); hEnd = (int) tw.endAsDouble(); } else { hStart = 0; hEnd = getHorizonBound(instance); } List<IVRPRequest> requests = instance.getRequests(); Collections.sort(requests, ObjectWithIdComparator.INSTANCE); int numDynReq = (int) (requests.size() * dynProp); // Draw the dynamic requests int[] dynReqIdx = Random.randomIndexes(requests.size(), numDynReq, getRandomStream()); Arrays.sort(dynReqIdx); // Split the request list in two lists ArrayList<IVRPRequest> staticReq = new ArrayList<IVRPRequest>(requests.size() - numDynReq); ArrayList<IVRPRequest> dynReq = new ArrayList<IVRPRequest>(numDynReq); ListIterator<IVRPRequest> it = requests.listIterator(); int dynIdx = 0; while (it.hasNext()) { if (dynIdx < dynReqIdx.length && it.nextIndex() == dynReqIdx[dynIdx]) { dynReq.add(it.next()); dynIdx++; } else { staticReq.add(it.next()); } } generateRDFile(instance.getName(), staticReq, dynReq, hStart, hEnd, destDir, "" + ((int) (100 * dynProp))); } /** * Generate a release date file and save it in the specified {@code path} using the format defined in * {@link #sNameFormat} with the {@code comment} as third argument * * @param instanceName * the name of the instance * @param staticReq * a list of static requests * @param dynReq * a list of dynamic requests * @param minReleaseDate * the minimum value for the release date * @param maxReleaseDate * the maximum value for the release date * @param destDir * the destination folder * @param comment * a comment for the file name * @throws IOException */ public void generateRDFile(String instanceName, List<IVRPRequest> staticReq, List<IVRPRequest> dynReq, int minReleaseDate, int maxReleaseDate, String destDir, String comment) throws IOException { FileBufferedWriter out = new FileBufferedWriter(String.format(sNameFormat, destDir, instanceName, comment)); // Write a comment line out.writeLine("# Instance %s - %s dynamic requests - %s static requests", instanceName, dynReq.size(), staticReq.size()); // #Dyn/Static Propotions out.writeLine("%-5s %s", "Dyn", "Stat"); out.writeLine("%-5s %s", dynReq.size(), staticReq.size()); // Headers out.writeLine("%-5s %s", "ID", "RD"); // Write static requests for (IVRPRequest r : staticReq) { out.writeLine("%-5s %s", r.getID(), -1); } // Write dynamic requests for (IVRPRequest r : dynReq) { out.writeLine("%-5s %s", r.getID(), getRandomStream().nextInt(minReleaseDate, maxReleaseDate)); } // Flush and close out.flush(); out.close(); } /** * Estimate a bound on the planning horizon length by constructing a solution and JAVADOC * * @param instance * @return */ protected int getHorizonBound(IVRPInstance instance) { CWParameters params = new CWParameters(); params.set(CWParameters.ALGORITHM_CLASS, RandomizedSavingsHeuristic.class); params.set(CWParameters.CTR_HANDLER_CLASS, ConstraintHandler.class); ClarkeAndWrightHeuristic<Solution<ArrayListRoute>> cw = new ClarkeAndWrightHeuristic<Solution<ArrayListRoute>>( params); cw.getConstraintHandler().addConstraint(new CapacityConstraint<Solution<ArrayListRoute>>()); cw.initialize(instance); cw.run(); // A correction factor in the case of limited fleet (removed for now) // -> More routes => underestimated bound => easier problem as more // requests will be disclosed early double correction = 1; if (!instance.getFleet().isUnlimited()) { boolean feas = cw.getSavingsAlgo().repairSolutionForLimitedFleet(); // correction = cw.getSolution().getRouteCount() // / instance.getFleet().size(); } Solution<ArrayListRoute> sol = cw.getSolution(); int maxDur = 0; for (ArrayListRoute r : sol) { if (r.length() < 2) continue; double dur = 0; ListIterator<INodeVisit> it = r.iterator(); INodeVisit pred = it.next(); dur += pred.getServiceTime(); while (it.hasNext()) { INodeVisit node = it.next(); dur += node.getServiceTime(); dur += instance.getCostDelegate().getTravelTime(pred, node, r.getVehicle()); pred = node; } if (dur > maxDur) maxDur = (int) dur; } return (int) (maxDur * correction); } /** * Generate the release date files for a collection of instances * * @param instances * @param dynProp * @param destDir * @param stream */ public static void generateRDFFiles(Collection<IVRPInstance> instances, double dynProp, String destDir, RandomStream stream) { DVRPReleaseDateGenerator gen = new DVRPReleaseDateGenerator(stream); for (IVRPInstance i : instances) { try { gen.generateRDFile(i, dynProp, destDir); Logging.getBaseLogger().info( "DVRPReleaseDateGenerator.generateRDFFiles: write rd file for instance %s (dynProp: %s)", i.getName(), dynProp); } catch (IOException e) { Logging.getBaseLogger().exception("DVRPReleaseDateGenerator.generateRDFFiles", e); } } } public static void main(String[] args) { LoggerHelper.setupRootLogger(LoggerHelper.LEVEL_WARN, LoggerHelper.LEVEL_WARN, false); String sourceDir = "../Instances/cvrp/christofides-mingozzi-toth"; String filePattern = "vrpnc.+txt"; FlatFilePersistenceHelper reader = new ChristofidesPersistenceHelper(); double dynProp = 0.1; String destDir = "../Instances/dvrp/pillac"; MRG32k3a stream = new MRG32k3a(); int firstSeed = sourceDir.hashCode(); if (firstSeed == 0) firstSeed = 1; stream.setSeed(new long[] { firstSeed, 2, 3, 4, 5, 6 }); try { List<File> files = Utilities.listFiles(sourceDir, filePattern); List<IVRPInstance> instances = new ArrayList<IVRPInstance>(files.size()); for (File f : files) { try { instances.add(reader.readInstance(f)); System.out.println("Added instance " + f); } catch (IOException e) { e.printStackTrace(); } } generateRDFFiles(instances, dynProp, destDir, stream); } catch (FileNotFoundException e) { e.printStackTrace(); } System.out.println("FINISHED"); } }