From de8689060a66cf891ef200c8ae2eb8feded47325 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 14 Oct 2015 18:26:58 +0200 Subject: [PATCH] speed up regret insertion with breaks --- .../algorithm/recreate/RegretInsertion.java | 153 +++++++++++++++++- ...leTypeDependentJobInsertionCalculator.java | 7 + 2 files changed, 155 insertions(+), 5 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java index c7736e86..9bafffd1 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java @@ -27,10 +27,7 @@ import jsprit.core.problem.solution.route.VehicleRoute; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; +import java.util.*; /** * Insertion based on regret approach. @@ -185,6 +182,33 @@ public class RegretInsertion extends AbstractInsertionStrategy { } + static class VersionedInsertionData { + + private InsertionData iData; + + private VehicleRoute route; + + private int version; + + public VersionedInsertionData(InsertionData iData, int version, VehicleRoute route) { + this.iData = iData; + this.version = version; + this.route = route; + } + + public InsertionData getiData() { + return iData; + } + + public int getVersion() { + return version; + } + + public VehicleRoute getRoute() { + return route; + } + } + private static Logger logger = LogManager.getLogger(RegretInsertion.class); private ScoringFunction scoringFunction; @@ -192,6 +216,7 @@ public class RegretInsertion extends AbstractInsertionStrategy { private JobInsertionCostsCalculator insertionCostsCalculator; + /** * Sets the scoring function. *

@@ -247,17 +272,35 @@ public class RegretInsertion extends AbstractInsertionStrategy { } List jobs = new ArrayList(unassignedJobs); + PriorityQueue[] priorityQueues = new PriorityQueue[vrp.getJobs().values().size() + 2]; + VehicleRoute lastModified = null; + boolean firstRun = true; + int updateRound = 0; + Map updates = new HashMap(); while (!jobs.isEmpty()) { List unassignedJobList = new ArrayList(jobs); List badJobList = new ArrayList(); - ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList); + if(firstRun){ + firstRun = false; + updateInsertionData(priorityQueues, routes, unassignedJobList, badJobList, updateRound, updates); + } + else{ + updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, badJobList, updateRound, updates); + } + updateRound++; + ScoredJob bestScoredJob = getBest(priorityQueues,updates,unassignedJobList,badJobList); +// InsertionData d = insertionCostsCalculator.getInsertionData(bestScoredJob.getRoute(), bestScoredJob.getJob(), NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); +// +// ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList); if (bestScoredJob != null) { if (bestScoredJob.isNewRoute()) { routes.add(bestScoredJob.getRoute()); } insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); jobs.remove(bestScoredJob.getJob()); + lastModified = bestScoredJob.getRoute(); } + else throw new IllegalStateException("fooo"); for (Job bad : badJobList) { jobs.remove(bad); badJobs.add(bad); @@ -266,6 +309,106 @@ public class RegretInsertion extends AbstractInsertionStrategy { return badJobs; } + private ScoredJob getBest(PriorityQueue[] priorityQueues, Map updates, List unassignedJobList, List badJobs) { + ScoredJob bestScoredJob = null; + for(Job j : unassignedJobList){ + VehicleRoute bestRoute = null; + InsertionData best = null; + InsertionData secondBest = null; + PriorityQueue priorityQueue = priorityQueues[j.getIndex()]; + Iterator iterator = priorityQueue.iterator(); + while(iterator.hasNext()){ + VersionedInsertionData versionedIData = iterator.next(); + if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue; + int currentDataVersion = updates.get(versionedIData.getRoute()); + if(versionedIData.getVersion() == currentDataVersion){ + if(best == null) { + best = versionedIData.getiData(); + bestRoute = versionedIData.getRoute(); + } + else { + secondBest = versionedIData.getiData(); + break; + } + } + } + VehicleRoute emptyRoute = VehicleRoute.emptyRoute(); + InsertionData iData = insertionCostsCalculator.getInsertionData(emptyRoute, j, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); + if(!(iData instanceof InsertionData.NoInsertionFound)){ + if (best == null) { + best = iData; + bestRoute = emptyRoute; + } else if (iData.getInsertionCost() < best.getInsertionCost()) { + secondBest = best; + best = iData; + bestRoute = emptyRoute; + } else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) { + secondBest = iData; + } + } + if (best == null) { + badJobs.add(j); + continue; + } + double score = score(j, best, secondBest, scoringFunction); + ScoredJob scoredJob; + if (bestRoute == emptyRoute) { + scoredJob = new ScoredJob(j, score, best, bestRoute, true); + } else scoredJob = new ScoredJob(j, score, best, bestRoute, false); + + if(bestScoredJob == null){ + bestScoredJob = scoredJob; + } + else if(scoredJob.getScore() > bestScoredJob.getScore()){ + bestScoredJob = scoredJob; + } + } + return bestScoredJob; + } + + private Comparator getComparator(){ + return new Comparator() { + @Override + public int compare(VersionedInsertionData o1, VersionedInsertionData o2) { + if(o1.getiData().getInsertionCost() < o2.getiData().getInsertionCost()) return -1; + return 1; + } + }; + } + + private void updateInsertionData(PriorityQueue[] priorityQueues, Collection routes, List unassignedJobList, List badJobList, int updateRound, Map updates) { + for (Job unassignedJob : unassignedJobList) { + if(priorityQueues[unassignedJob.getIndex()] == null){ + priorityQueues[unassignedJob.getIndex()] = new PriorityQueue(unassignedJobList.size(), getComparator()); + } + for(VehicleRoute route : routes) { + + InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); + priorityQueues[unassignedJob.getIndex()].add(new VersionedInsertionData(iData,updateRound,route)); + updates.put(route,updateRound); + } + +// +// +// +// ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction); +// if (scoredJob instanceof BadJob) { +// badJobs.add(unassignedJob); +// continue; +// } +// if (bestScoredJob == null) bestScoredJob = scoredJob; +// else { +// if (scoredJob.getScore() > bestScoredJob.getScore()) { +// bestScoredJob = scoredJob; +// } else if (scoredJob.getScore() == bestScoredJob.getScore()) { +// if (scoredJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) { +// bestScoredJob = scoredJob; +// } +// } +// } + } + } + private VehicleRoute findRoute(Collection routes, Job job) { for(VehicleRoute r : routes){ if(r.getVehicle().getBreak() == job) return r; diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java index dcf57359..6dc17a48 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java @@ -93,6 +93,9 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo } public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) { + if(vehicle != null){ + return insertionCalculator.getInsertionData(currentRoute, jobToInsert, vehicle, newVehicleDepartureTime, driver, bestKnownCost); + } Vehicle selectedVehicle = currentRoute.getVehicle(); Driver selectedDriver = currentRoute.getDriver(); InsertionData bestIData = InsertionData.createEmptyInsertionData(); @@ -122,6 +125,10 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo return bestIData; } + VehicleFleetManager getFleetManager(){ + return fleetManager; + } + private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) { return initialVehicleIds.contains(selectedVehicle.getId()); }