From d3510048d5bb46d723f761bb94e98cbf1fa1e5ce Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 14 Oct 2015 22:06:07 +0200 Subject: [PATCH] speed up regret insertion with breaks --- .../jsprit/core/algorithm/box/Jsprit.java | 1 + .../algorithm/recreate/InsertionBuilder.java | 5 +- .../algorithm/recreate/RegretInsertion.java | 53 ++++++++++++++++--- .../recreate/SwitchVehicleListener.java | 4 +- .../problem/vehicle/InfiniteVehicles.java | 9 +++- .../problem/vehicle/VehicleFleetManager.java | 1 + .../vehicle/VehicleFleetManagerImpl.java | 8 +++ .../recreate/RegretInsertionTest.java | 10 ++++ 8 files changed, 79 insertions(+), 12 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java index b10fe7ef..4287e723 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/box/Jsprit.java @@ -424,6 +424,7 @@ public class Jsprit { .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .setActivityInsertionCostCalculator(activityInsertion) .build(); + regretInsertion.setFleetManager(fm); scorer = getRegretScorer(vrp); regretInsertion.setScoringFunction(scorer); regret = regretInsertion; diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java index 8f2a7809..db23af02 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java @@ -166,7 +166,10 @@ public class InsertionBuilder { } } else if (strategy.equals(Strategy.REGRET)) { if (executor == null) { - insertion = new RegretInsertion(costCalculator, vrp); + RegretInsertion regret = new RegretInsertion(costCalculator, vrp); + regret.setFleetManager(fleetManager); + insertion = regret; + } else { insertion = new RegretInsertionConcurrent(costCalculator, vrp, executor); } 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 9bafffd1..175f4f3f 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 @@ -24,6 +24,9 @@ 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; @@ -215,7 +218,11 @@ public class RegretInsertion extends AbstractInsertionStrategy { private JobInsertionCostsCalculator insertionCostsCalculator; + private VehicleFleetManager fleetManager; + public void setFleetManager(VehicleFleetManager fleetManager) { + this.fleetManager = fleetManager; + } /** * Sets the scoring function. @@ -280,6 +287,7 @@ public class RegretInsertion extends AbstractInsertionStrategy { while (!jobs.isEmpty()) { List unassignedJobList = new ArrayList(jobs); List badJobList = new ArrayList(); + if(!firstRun && lastModified == null) throw new IllegalStateException("fooo"); if(firstRun){ firstRun = false; updateInsertionData(priorityQueues, routes, unassignedJobList, badJobList, updateRound, updates); @@ -289,9 +297,6 @@ public class RegretInsertion extends AbstractInsertionStrategy { } 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()); @@ -300,7 +305,7 @@ public class RegretInsertion extends AbstractInsertionStrategy { jobs.remove(bestScoredJob.getJob()); lastModified = bestScoredJob.getRoute(); } - else throw new IllegalStateException("fooo"); + else lastModified = null; for (Job bad : badJobList) { jobs.remove(bad); badJobs.add(bad); @@ -319,7 +324,30 @@ public class RegretInsertion extends AbstractInsertionStrategy { 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) { @@ -382,9 +410,20 @@ public class RegretInsertion extends AbstractInsertionStrategy { 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)); + 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); } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/SwitchVehicleListener.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/SwitchVehicleListener.java index 393dd01a..a25c2800 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/SwitchVehicleListener.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/SwitchVehicleListener.java @@ -16,11 +16,11 @@ class SwitchVehicleListener implements EventListener { if (event instanceof SwitchVehicle) { SwitchVehicle switchVehicle = (SwitchVehicle) event; if (vehiclesDifferent((SwitchVehicle) event)) { - logger.trace("switch vehicle (" + ((SwitchVehicle) event).getRoute().getVehicle().getId() + " to " + ((SwitchVehicle) event).getVehicle().getId() + ")"); + logger.trace("switch vehicle ({} to {})",((SwitchVehicle) event).getRoute().getVehicle().getId(),((SwitchVehicle) event).getVehicle().getId()); Break aBreak = ((SwitchVehicle) event).getRoute().getVehicle().getBreak(); if (aBreak != null) { boolean removed = ((SwitchVehicle) event).getRoute().getTourActivities().removeJob(aBreak); - if (removed) logger.trace("remove " + aBreak.getId()); + if (removed) logger.trace("remove {}",aBreak.getId()); } } switchVehicle.getRoute().setVehicleAndDepartureTime(switchVehicle.getVehicle(), ((SwitchVehicle) event).getDepartureTime()); diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java index 702e2b26..df60c65b 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java @@ -45,8 +45,8 @@ class InfiniteVehicles implements VehicleFleetManager { private void extractTypes(Collection vehicles) { for (Vehicle v : vehicles) { - VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills(), v.isReturnToDepot()); - types.put(typeKey, v); +// VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocation().getId(), v.getEndLocation().getId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills(), v.isReturnToDepot()); + types.put(v.getVehicleTypeIdentifier(), v); // sortedTypes.add(typeKey); } } @@ -90,4 +90,9 @@ class InfiniteVehicles implements VehicleFleetManager { return vehicles; } + @Override + public Vehicle getAvailableVehicle(VehicleTypeKey vehicleTypeIdentifier) { + return types.get(vehicleTypeIdentifier); + } + } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManager.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManager.java index aadd1799..7fefb989 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManager.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManager.java @@ -66,4 +66,5 @@ public interface VehicleFleetManager { public Collection getAvailableVehicles(Vehicle withoutThisType); + public Vehicle getAvailableVehicle(VehicleTypeKey vehicleTypeIdentifier); } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java index d5ee9664..4a5cd54e 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java @@ -143,6 +143,14 @@ class VehicleFleetManagerImpl implements VehicleFleetManager { return vehicles; } + @Override + public Vehicle getAvailableVehicle(VehicleTypeKey vehicleTypeIdentifier) { + if(!vehicleTypes[vehicleTypeIdentifier.getIndex()].isEmpty()){ + return vehicleTypes[vehicleTypeIdentifier.getIndex()].getVehicle(); + } + return null; + } + /* (non-Javadoc) * @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#lock(org.matsim.contrib.freight.vrp.basics.Vehicle) */ diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/RegretInsertionTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/RegretInsertionTest.java index f7901719..cf2c8bce 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/RegretInsertionTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/RegretInsertionTest.java @@ -26,7 +26,9 @@ import jsprit.core.problem.job.Service; import jsprit.core.problem.job.Shipment; import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.FiniteFleetManagerFactory; import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleFleetManager; import jsprit.core.problem.vehicle.VehicleImpl; import jsprit.core.util.Coordinate; import junit.framework.Assert; @@ -45,8 +47,10 @@ public class RegretInsertionTest { VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build(); VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addVehicle(v).build(); + VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); JobInsertionCostsCalculator calculator = getCalculator(vrp); RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp); + regretInsertion.setFleetManager(fm); Collection routes = new ArrayList(); regretInsertion.insertJobs(routes, vrp.getJobs().values()); @@ -61,8 +65,10 @@ public class RegretInsertionTest { VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build(); VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addVehicle(v).build(); + VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); JobInsertionCostsCalculator calculator = getCalculator(vrp); RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp); + regretInsertion.setFleetManager(fm); Collection routes = new ArrayList(); regretInsertion.insertJobs(routes, vrp.getJobs().values()); @@ -77,8 +83,10 @@ public class RegretInsertionTest { VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build(); final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addVehicle(v).build(); + VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); JobInsertionCostsCalculator calculator = getCalculator(vrp); RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp); + regretInsertion.setFleetManager(fm); Collection routes = new ArrayList(); CkeckJobSequence position = new CkeckJobSequence(2, s1); @@ -102,8 +110,10 @@ public class RegretInsertionTest { VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build(); final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addVehicle(v).build(); + VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); JobInsertionCostsCalculator calculator = getShipmentCalculator(vrp); RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp); + regretInsertion.setFleetManager(fm); Collection routes = new ArrayList(); CkeckJobSequence position = new CkeckJobSequence(2, s2);