diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/box/ConcurrentInsertionNoiseMaker.java b/jsprit-core/src/main/java/jsprit/core/algorithm/box/ConcurrentInsertionNoiseMaker.java index 11b86f5a..1c681224 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/box/ConcurrentInsertionNoiseMaker.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/box/ConcurrentInsertionNoiseMaker.java @@ -49,9 +49,9 @@ class ConcurrentInsertionNoiseMaker implements SoftActivityConstraint, Iteration @Override public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { -// if (makeNoise) { -// return noiseLevel * maxCosts * randomArray[newAct.getIndex()].nextDouble(); -// } + if (makeNoise) { + return noiseLevel * maxCosts * randomArray[newAct.getIndex()].nextDouble(); + } return 0; } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/box/InsertionNoiseMaker.java b/jsprit-core/src/main/java/jsprit/core/algorithm/box/InsertionNoiseMaker.java index dbf40735..4228bfa0 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/box/InsertionNoiseMaker.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/box/InsertionNoiseMaker.java @@ -49,9 +49,9 @@ class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsList @Override public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { -// if (makeNoise) { -// return noiseLevel * maxCosts * random.nextDouble(); -// } + if (makeNoise) { + return noiseLevel * maxCosts * random.nextDouble(); + } return 0; } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/DefaultScorer.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/DefaultScorer.java new file mode 100644 index 00000000..44c4f1c7 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/DefaultScorer.java @@ -0,0 +1,83 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.problem.Location; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.job.Shipment; + +/** + * Created by schroeder on 15/10/15. + */ +public class DefaultScorer implements ScoringFunction { + + private VehicleRoutingProblem vrp; + + private double tw_param = -0.5; + + private double depotDistance_param = +0.1; + + private double minTimeWindowScore = -100000; + + public DefaultScorer(VehicleRoutingProblem vrp) { + this.vrp = vrp; + } + + public void setTimeWindowParam(double tw_param) { + this.tw_param = tw_param; + } + + public void setDepotDistanceParam(double depotDistance_param) { + this.depotDistance_param = depotDistance_param; + } + + @Override + public double score(InsertionData best, Job job) { + double score; + if (job instanceof Service) { + score = scoreService(best, job); + } else if (job instanceof Shipment) { + score = scoreShipment(best, job); + } else throw new IllegalStateException("not supported"); + return score; + } + + private double scoreShipment(InsertionData best, Job job) { + Shipment shipment = (Shipment) job; + double maxDepotDistance_1 = Math.max( + getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getPickupLocation()), + getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getDeliveryLocation()) + ); + double maxDepotDistance_2 = Math.max( + getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getPickupLocation()), + getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getDeliveryLocation()) + ); + double maxDepotDistance = Math.max(maxDepotDistance_1, maxDepotDistance_2); + double minTimeToOperate = Math.min(shipment.getPickupTimeWindow().getEnd() - shipment.getPickupTimeWindow().getStart(), + shipment.getDeliveryTimeWindow().getEnd() - shipment.getDeliveryTimeWindow().getStart()); + return Math.max(tw_param * minTimeToOperate, minTimeWindowScore) + depotDistance_param * maxDepotDistance; + } + + private double scoreService(InsertionData best, Job job) { + Location location = ((Service) job).getLocation(); + double maxDepotDistance = 0; + if (location != null) { + maxDepotDistance = Math.max( + getDistance(best.getSelectedVehicle().getStartLocation(), location), + getDistance(best.getSelectedVehicle().getEndLocation(), location) + ); + } + return Math.max(tw_param * (((Service) job).getTimeWindow().getEnd() - ((Service) job).getTimeWindow().getStart()), minTimeWindowScore) + + depotDistance_param * maxDepotDistance; + } + + + private double getDistance(Location loc1, Location loc2) { + return vrp.getTransportCosts().getTransportCost(loc1, loc2, 0., null, null); + } + + @Override + public String toString() { + return "[name=defaultScorer][twParam=" + tw_param + "][depotDistanceParam=" + depotDistance_param + "]"; + } +} diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionDataUpdater.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionDataUpdater.java new file mode 100644 index 00000000..09bf21e0 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionDataUpdater.java @@ -0,0 +1,147 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.problem.job.Job; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleFleetManager; +import jsprit.core.problem.vehicle.VehicleImpl; + +import java.util.*; + +/** + * Created by schroeder on 15/10/15. + */ +class InsertionDataUpdater { + + static void update(VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet insertionDataSet, int updateRound, Map updates, Job unassignedJob, Collection routes) { + for(VehicleRoute route : routes) { + Collection relevantVehicles = new ArrayList(); + if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { + relevantVehicles.add(route.getVehicle()); + relevantVehicles.addAll(fleetManager.getAvailableVehicles(route.getVehicle())); + } else relevantVehicles.addAll(fleetManager.getAvailableVehicles()); + for (Vehicle v : relevantVehicles) { + double depTime = v.getEarliestDeparture(); + InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, v, depTime, route.getDriver(), Double.MAX_VALUE); + if (iData instanceof InsertionData.NoInsertionFound) { + continue; + } + insertionDataSet.add(new VersionedInsertionData(iData, updateRound, route)); + } + updates.put(route, updateRound); + } + } + + static VehicleRoute findRoute(Collection routes, Job job) { + for(VehicleRoute r : routes){ + if(r.getVehicle().getBreak() == job) return r; + } + return null; + } + + static Comparator getComparator(){ + return new Comparator() { + @Override + public int compare(VersionedInsertionData o1, VersionedInsertionData o2) { + if(o1.getiData().getInsertionCost() < o2.getiData().getInsertionCost()) return -1; + return 1; + } + }; + } + + static ScoredJob getBest(VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet[] priorityQueues, Map updates, List unassignedJobList, List badJobs) { + ScoredJob bestScoredJob = null; + for(Job j : unassignedJobList){ + VehicleRoute bestRoute = null; + InsertionData best = null; + InsertionData secondBest = null; + TreeSet priorityQueue = priorityQueues[j.getIndex()]; + Iterator iterator = priorityQueue.iterator(); + while(iterator.hasNext()){ + VersionedInsertionData versionedIData = iterator.next(); + if(bestRoute != null){ + if(versionedIData.getRoute() == bestRoute){ + continue; + } + } + if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue; + if(versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) { + if (fleetManager.isLocked(versionedIData.getiData().getSelectedVehicle())) { + Vehicle available = fleetManager.getAvailableVehicle(versionedIData.getiData().getSelectedVehicle().getVehicleTypeIdentifier()); + if (available != null) { + InsertionData oldData = versionedIData.getiData(); + InsertionData newData = new InsertionData(oldData.getInsertionCost(), oldData.getPickupInsertionIndex(), + oldData.getDeliveryInsertionIndex(), available, oldData.getSelectedDriver()); + newData.setVehicleDepartureTime(oldData.getVehicleDepartureTime()); + for(Event e : oldData.getEvents()){ + if(e instanceof SwitchVehicle){ + newData.getEvents().add(new SwitchVehicle(versionedIData.getRoute(),available,oldData.getVehicleDepartureTime())); + } + else newData.getEvents().add(e); + } + versionedIData = new VersionedInsertionData(newData, versionedIData.getVersion(), versionedIData.getRoute()); + } else 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, null, -1, null, 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; + } + + static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) { + if (best == null) { + throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); + } + double score; + if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob + //if only one vehicle, I want the job to be inserted with min iCosts + //if there are more vehicles, I want this job to be prioritized since there are no alternatives + score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob); + } else { + score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); + } + return score; + } + +} 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 12335b1b..1c7ffe16 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 @@ -17,16 +17,11 @@ package jsprit.core.algorithm.recreate; -import jsprit.core.problem.Location; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.job.Break; import jsprit.core.problem.job.Job; -import jsprit.core.problem.job.Service; -import jsprit.core.problem.job.Shipment; import jsprit.core.problem.solution.route.VehicleRoute; -import jsprit.core.problem.vehicle.Vehicle; import jsprit.core.problem.vehicle.VehicleFleetManager; -import jsprit.core.problem.vehicle.VehicleImpl; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -44,174 +39,6 @@ import java.util.*; */ public class RegretInsertion extends AbstractInsertionStrategy { - static class ScoredJob { - - private Job job; - - private double score; - - private InsertionData insertionData; - - private VehicleRoute route; - - private boolean newRoute; - - - ScoredJob(Job job, double score, InsertionData insertionData, VehicleRoute route, boolean isNewRoute) { - this.job = job; - this.score = score; - this.insertionData = insertionData; - this.route = route; - this.newRoute = isNewRoute; - } - - public boolean isNewRoute() { - return newRoute; - } - - public Job getJob() { - return job; - } - - public double getScore() { - return score; - } - - public InsertionData getInsertionData() { - return insertionData; - } - - public VehicleRoute getRoute() { - return route; - } - } - - static class BadJob extends ScoredJob { - - BadJob(Job job) { - super(job, 0., null, null, false); - } - } - - /** - * Scorer to include other impacts on score such as time-window length or distance to depot. - * - * @author schroeder - */ - static interface ScoringFunction { - - public double score(InsertionData best, Job job); - - } - - /** - * Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score. - *

- *

This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job) - * - * @author schroeder - */ - public static class DefaultScorer implements ScoringFunction { - - private VehicleRoutingProblem vrp; - - private double tw_param = -0.5; - - private double depotDistance_param = +0.1; - - private double minTimeWindowScore = -100000; - - public DefaultScorer(VehicleRoutingProblem vrp) { - this.vrp = vrp; - } - - public void setTimeWindowParam(double tw_param) { - this.tw_param = tw_param; - } - - public void setDepotDistanceParam(double depotDistance_param) { - this.depotDistance_param = depotDistance_param; - } - - @Override - public double score(InsertionData best, Job job) { - double score; - if (job instanceof Service) { - score = scoreService(best, job); - } else if (job instanceof Shipment) { - score = scoreShipment(best, job); - } else throw new IllegalStateException("not supported"); - return score; - } - - private double scoreShipment(InsertionData best, Job job) { - Shipment shipment = (Shipment) job; - double maxDepotDistance_1 = Math.max( - getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getPickupLocation()), - getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getDeliveryLocation()) - ); - double maxDepotDistance_2 = Math.max( - getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getPickupLocation()), - getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getDeliveryLocation()) - ); - double maxDepotDistance = Math.max(maxDepotDistance_1, maxDepotDistance_2); - double minTimeToOperate = Math.min(shipment.getPickupTimeWindow().getEnd() - shipment.getPickupTimeWindow().getStart(), - shipment.getDeliveryTimeWindow().getEnd() - shipment.getDeliveryTimeWindow().getStart()); - return Math.max(tw_param * minTimeToOperate, minTimeWindowScore) + depotDistance_param * maxDepotDistance; - } - - private double scoreService(InsertionData best, Job job) { - Location location = ((Service) job).getLocation(); - double maxDepotDistance = 0; - if (location != null) { - maxDepotDistance = Math.max( - getDistance(best.getSelectedVehicle().getStartLocation(), location), - getDistance(best.getSelectedVehicle().getEndLocation(), location) - ); - } - return Math.max(tw_param * (((Service) job).getTimeWindow().getEnd() - ((Service) job).getTimeWindow().getStart()), minTimeWindowScore) + - depotDistance_param * maxDepotDistance; - } - - - private double getDistance(Location loc1, Location loc2) { - return vrp.getTransportCosts().getTransportCost(loc1, loc2, 0., null, null); - } - - @Override - public String toString() { - return "[name=defaultScorer][twParam=" + tw_param + "][depotDistanceParam=" + depotDistance_param + "]"; - } - - } - - 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; @@ -262,7 +89,7 @@ public class RegretInsertion extends AbstractInsertionStrategy { while (jobIterator.hasNext()){ Job job = jobIterator.next(); if(job instanceof Break){ - VehicleRoute route = findRoute(routes,job); + VehicleRoute route = InsertionDataUpdater.findRoute(routes, job); if(route == null){ badJobs.add(job); } @@ -296,7 +123,7 @@ public class RegretInsertion extends AbstractInsertionStrategy { updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, badJobList, updateRound, updates); } updateRound++; - ScoredJob bestScoredJob = getBest(priorityQueues,updates,unassignedJobList,badJobList); + ScoredJob bestScoredJob = InsertionDataUpdater.getBest(fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList); if (bestScoredJob != null) { if (bestScoredJob.isNewRoute()) { routes.add(bestScoredJob.getRoute()); @@ -314,238 +141,15 @@ public class RegretInsertion extends AbstractInsertionStrategy { return badJobs; } - private ScoredJob getBest(TreeSet[] priorityQueues, Map updates, List unassignedJobList, List badJobs) { - ScoredJob bestScoredJob = null; - for(Job j : unassignedJobList){ - VehicleRoute bestRoute = null; - InsertionData best = null; - InsertionData secondBest = null; - TreeSet priorityQueue = priorityQueues[j.getIndex()]; - Iterator iterator = priorityQueue.iterator(); - while(iterator.hasNext()){ - VersionedInsertionData versionedIData = iterator.next(); - if(bestRoute != null){ - if(versionedIData.getRoute() == bestRoute){ - continue; - } - } - if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue; - if(versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) { - if (fleetManager.isLocked(versionedIData.getiData().getSelectedVehicle())) { - Vehicle available = fleetManager.getAvailableVehicle(versionedIData.getiData().getSelectedVehicle().getVehicleTypeIdentifier()); - if (available != null) { - InsertionData oldData = versionedIData.getiData(); - InsertionData newData = new InsertionData(oldData.getInsertionCost(), oldData.getPickupInsertionIndex(), - oldData.getDeliveryInsertionIndex(), available, oldData.getSelectedDriver()); - newData.setVehicleDepartureTime(oldData.getVehicleDepartureTime()); - for(Event e : oldData.getEvents()){ - if(e instanceof SwitchVehicle){ - newData.getEvents().add(new SwitchVehicle(versionedIData.getRoute(),available,oldData.getVehicleDepartureTime())); - } - else newData.getEvents().add(e); - } - versionedIData = new VersionedInsertionData(newData, versionedIData.getVersion(), versionedIData.getRoute()); - } else 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; - } -// else { -// if(best != null && secondBest != null) { -// System.out.println("best " + best.getInsertionCost() + ", secondBest: " + secondBest.getInsertionCost()); -// } -// } - 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(TreeSet[] priorityQueues, Collection routes, List unassignedJobList, List badJobList, int updateRound, Map updates) { for (Job unassignedJob : unassignedJobList) { if(priorityQueues[unassignedJob.getIndex()] == null){ - priorityQueues[unassignedJob.getIndex()] = new TreeSet(getComparator()); + priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator()); } - for(VehicleRoute route : routes) { - Collection relevantVehicles = new ArrayList(); - if(!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { - relevantVehicles.add(route.getVehicle()); - relevantVehicles.addAll(fleetManager.getAvailableVehicles(route.getVehicle())); - } - else relevantVehicles.addAll(fleetManager.getAvailableVehicles()); - for (Vehicle v : relevantVehicles) { - double depTime = v.getEarliestDeparture(); - InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, v, depTime, route.getDriver(), Double.MAX_VALUE); - if (iData instanceof InsertionData.NoInsertionFound) { - continue; - } - 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; -// } -// } -// } + InsertionDataUpdater.update(fleetManager,insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, updates, unassignedJob, routes); } } - private VehicleRoute findRoute(Collection routes, Job job) { - for(VehicleRoute r : routes){ - if(r.getVehicle().getBreak() == job) return r; - } - return null; - } - - private ScoredJob nextJob(Collection routes, Collection unassignedJobList, List badJobs) { - ScoredJob bestScoredJob = null; - for (Job unassignedJob : unassignedJobList) { - 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; - } - } - } - } - return bestScoredJob; - } - - static ScoredJob getScoredJob(Collection routes, Job unassignedJob, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction) { - InsertionData best = null; - InsertionData secondBest = null; - VehicleRoute bestRoute = null; - - double benchmark = Double.MAX_VALUE; - for (VehicleRoute route : routes) { - if (secondBest != null) { - benchmark = secondBest.getInsertionCost(); - } - InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark); - if (iData instanceof InsertionData.NoInsertionFound) continue; - if (best == null) { - best = iData; - bestRoute = route; - } else if (iData.getInsertionCost() < best.getInsertionCost()) { - secondBest = best; - best = iData; - bestRoute = route; - } else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) { - secondBest = iData; - } - } - - VehicleRoute emptyRoute = VehicleRoute.emptyRoute(); - InsertionData iData = insertionCostsCalculator.getInsertionData(emptyRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark); - 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) { - return new RegretInsertion.BadJob(unassignedJob); - } - double score = score(unassignedJob, best, secondBest, scoringFunction); - ScoredJob scoredJob; - if (bestRoute == emptyRoute) { - scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true); - } else scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false); - return scoredJob; - } - - - static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) { - if (best == null) { - throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); - } - double score; - if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob - //if only one vehicle, I want the job to be inserted with min iCosts - //if there are more vehicles, I want this job to be prioritized since there are no alternatives - score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob); - } else { - score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); - } - return score; - } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java index a08f7f46..b972d1af 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java @@ -17,21 +17,17 @@ package jsprit.core.algorithm.recreate; -import jsprit.core.algorithm.recreate.RegretInsertion.DefaultScorer; -import jsprit.core.algorithm.recreate.RegretInsertion.ScoredJob; -import jsprit.core.algorithm.recreate.RegretInsertion.ScoringFunction; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.job.Break; import jsprit.core.problem.job.Job; import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.vehicle.VehicleFleetManager; 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.concurrent.*; +import java.util.*; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; /** * Insertion based on regret approach. @@ -54,6 +50,13 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy { private final ExecutorCompletionService completionService; + private VehicleFleetManager fleetManager; + + + public void setFleetManager(VehicleFleetManager fleetManager) { + this.fleetManager = fleetManager; + } + /** * Sets the scoring function. *

@@ -95,7 +98,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy { while (jobIterator.hasNext()){ Job job = jobIterator.next(); if(job instanceof Break){ - VehicleRoute route = findRoute(routes,job); + VehicleRoute route = InsertionDataUpdater.findRoute(routes, job); if(route == null){ badJobs.add(job); } @@ -112,72 +115,53 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy { } List jobs = new ArrayList(unassignedJobs); + TreeSet[] priorityQueues = new TreeSet[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 && lastModified == null) throw new IllegalStateException("fooo"); + if(firstRun){ + firstRun = false; + updateInsertionData(priorityQueues, routes, unassignedJobList, badJobList, updateRound, updates); + } + else{ + updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, badJobList, updateRound, updates); + } + updateRound++; + ScoredJob bestScoredJob = InsertionDataUpdater.getBest(fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, 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(); } - for (Job j : badJobList) { - jobs.remove(j); - badJobs.add(j); + else lastModified = null; + for (Job bad : badJobList) { + jobs.remove(bad); + badJobs.add(bad); } } return badJobs; } - private ScoredJob nextJob(final Collection routes, List unassignedJobList, List badJobList) { - ScoredJob bestScoredJob = null; - - for (final Job unassignedJob : unassignedJobList) { - completionService.submit(new Callable() { - - @Override - public ScoredJob call() throws Exception { - return RegretInsertion.getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction); - } - - }); - } - - try { - for (int i = 0; i < unassignedJobList.size(); i++) { - Future fsj = completionService.take(); - ScoredJob sJob = fsj.get(); - if (sJob instanceof RegretInsertion.BadJob) { - badJobList.add(sJob.getJob()); - continue; - } - if (bestScoredJob == null) { - bestScoredJob = sJob; - } else if (sJob.getScore() > bestScoredJob.getScore()) { - bestScoredJob = sJob; - } else if (sJob.getScore() == bestScoredJob.getScore()) { - if (sJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) { - bestScoredJob = sJob; - } - } + private void updateInsertionData(TreeSet[] priorityQueues, Collection routes, List unassignedJobList, List badJobList, int updateRound, Map updates) { + for (Job unassignedJob : unassignedJobList) { + if(priorityQueues[unassignedJob.getIndex()] == null){ + priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator()); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - throw new RuntimeException(e); +// completionService.submit(ne) + InsertionDataUpdater.update(fleetManager,insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, updates, unassignedJob, routes); } - - return bestScoredJob; } - private VehicleRoute findRoute(Collection routes, Job job) { - for(VehicleRoute r : routes){ - if(r.getVehicle().getBreak() == job) return r; - } - return null; - } + + } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ScoredJob.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ScoredJob.java new file mode 100644 index 00000000..32d952e2 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ScoredJob.java @@ -0,0 +1,57 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.problem.job.Job; +import jsprit.core.problem.solution.route.VehicleRoute; + +/** + * Created by schroeder on 15/10/15. + */ +class ScoredJob { + + static class BadJob extends ScoredJob { + + BadJob(Job job) { + super(job, 0., null, null, false); + } + } + + private Job job; + + private double score; + + private InsertionData insertionData; + + private VehicleRoute route; + + private boolean newRoute; + + + ScoredJob(Job job, double score, InsertionData insertionData, VehicleRoute route, boolean isNewRoute) { + this.job = job; + this.score = score; + this.insertionData = insertionData; + this.route = route; + this.newRoute = isNewRoute; + } + + public boolean isNewRoute() { + return newRoute; + } + + public Job getJob() { + return job; + } + + public double getScore() { + return score; + } + + public InsertionData getInsertionData() { + return insertionData; + } + + public VehicleRoute getRoute() { + return route; + } + +} diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ScoringFunction.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ScoringFunction.java new file mode 100644 index 00000000..434de325 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ScoringFunction.java @@ -0,0 +1,12 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.problem.job.Job; + +/** + * Created by schroeder on 15/10/15. + */ +public interface ScoringFunction { + + public double score(InsertionData best, Job job); + +} diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VersionedInsertionData.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VersionedInsertionData.java new file mode 100644 index 00000000..fcc4aa3c --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/VersionedInsertionData.java @@ -0,0 +1,33 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.problem.solution.route.VehicleRoute; + +/** + * Created by schroeder on 15/10/15. + */ +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; + } +}