From 0b3b07a7de0e45ef47b25d80239ba52d9cd76a1c Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 13 Jul 2015 19:58:24 +0200 Subject: [PATCH] multiple tws --- .../recreate/ServiceInsertionCalculator.java | 16 ++- ...vityStartsAsSoonAsNextTimeWindowOpens.java | 19 ++-- ...eVehicleDependentPracticalTimeWindows.java | 2 + .../jsprit/core/util/ActivityTimeTracker.java | 20 +++- .../jsprit/core/util/CalculationUtils.java | 4 +- .../state/GetLatestArrivalTimeTest.java | 100 ++++++++++++++++-- .../UpdateVehicleDependentTimeWindowTest.java | 33 ++++++ .../test/resources/infiniteWriterV2Test.xml | 81 +++++++++----- .../instance/reader/BelhaizaReader.java | 2 +- 9 files changed, 219 insertions(+), 58 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java index 8d8b4a11..ce29371e 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java @@ -135,8 +135,10 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ } double actArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(),deliveryAct2Insert.getLocation(),prevActStartTime,newDriver,newVehicle); Collection timeWindows = service.getTimeWindows(actArrTime); + TimeWindow timeWindow = getNextTimeWindow(actArrTime,timeWindows); + if(timeWindow == null) break; boolean not_fulfilled_break = true; - for(TimeWindow timeWindow : timeWindows) { +// for(TimeWindow timeWindow : timeWindows) { deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(timeWindow.getStart()); deliveryAct2Insert.setTheoreticalLatestOperationStartTime(timeWindow.getEnd()); ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); @@ -153,7 +155,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ } else if (status.equals(ConstraintsStatus.NOT_FULFILLED)) { not_fulfilled_break = false; } - } +// } if(not_fulfilled_break) break; double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle); prevActStartTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct); @@ -172,4 +174,14 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{ return insertionData; } + private TimeWindow getNextTimeWindow(double actArrTime, Collection timeWindows) { + for(TimeWindow tw : timeWindows){ + if(actArrTime >= tw.getStart() && actArrTime <= tw.getEnd()) return tw; + else if(actArrTime < tw.getStart()){ + return tw; + } + } + return null; + } + } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/ActivityStartsAsSoonAsNextTimeWindowOpens.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/ActivityStartsAsSoonAsNextTimeWindowOpens.java index b8d626e4..fb824ec0 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/ActivityStartsAsSoonAsNextTimeWindowOpens.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/ActivityStartsAsSoonAsNextTimeWindowOpens.java @@ -10,22 +10,19 @@ public class ActivityStartsAsSoonAsNextTimeWindowOpens implements ActivityStartS @Override public double getActivityStartTime(TourActivity activity, double arrivalTime) { - boolean next = false; - for(TimeWindow tw : activity.getTimeWindows()){ - if(next){ - return Math.max(tw.getStart(),arrivalTime); - } + TimeWindow last = null; + for(int i=activity.getTimeWindows().size()-1; i >= 0; i--){ + TimeWindow tw = activity.getTimeWindows().get(i); if(tw.getStart() <= arrivalTime && tw.getEnd() >= arrivalTime){ return arrivalTime; } - else if(tw.getEnd() < arrivalTime){ - next = true; - } - else if(tw.getStart() > arrivalTime){ - return tw.getStart(); + else if(arrivalTime > tw.getEnd()){ + if(last != null) return last.getStart(); + else return arrivalTime; } + last = tw; } - return arrivalTime; + return Math.max(arrivalTime,last.getStart()); } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java index 1ea1ca46..0ea69524 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateVehicleDependentPracticalTimeWindows.java @@ -75,6 +75,7 @@ public class UpdateVehicleDependentPracticalTimeWindows implements ReverseActivi vehicles = vehiclesToUpdate.get(route); for(Vehicle vehicle : vehicles){ latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = vehicle.getLatestArrival(); +// System.out.println("vehicle latest arr time: " + latest_arrTimes_at_prevAct); location_of_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = vehicle.getEndLocation(); } } @@ -87,6 +88,7 @@ public class UpdateVehicleDependentPracticalTimeWindows implements ReverseActivi double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocation(), prevLocation, latestArrTimeAtPrevAct, route.getDriver(), vehicle) - activity.getOperationTime(); double latestArrivalTime = getLatestArrivalTime(activity.getTimeWindows(),potentialLatestArrivalTimeAtCurrAct); +// System.out.println("update latest: " + latestArrivalTime + " activity: " + activity); stateManager.putInternalTypedActivityState(activity, vehicle, InternalStates.LATEST_OPERATION_START_TIME, latestArrivalTime); latest_arrTimes_at_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = latestArrivalTime; location_of_prevAct[vehicle.getVehicleTypeIdentifier().getIndex()] = activity.getLocation(); diff --git a/jsprit-core/src/main/java/jsprit/core/util/ActivityTimeTracker.java b/jsprit-core/src/main/java/jsprit/core/util/ActivityTimeTracker.java index 2ad2337a..9fda4ea9 100644 --- a/jsprit-core/src/main/java/jsprit/core/util/ActivityTimeTracker.java +++ b/jsprit-core/src/main/java/jsprit/core/util/ActivityTimeTracker.java @@ -18,7 +18,7 @@ package jsprit.core.util; import jsprit.core.algorithm.state.ActivityStartAsSoonAsArrived; import jsprit.core.algorithm.state.ActivityStartStrategy; -import jsprit.core.algorithm.state.ActivityStartsAsSoonAsTimeWindowOpens; +import jsprit.core.algorithm.state.ActivityStartsAsSoonAsNextTimeWindowOpens; import jsprit.core.problem.cost.ForwardTransportTime; import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.activity.ActivityVisitor; @@ -51,16 +51,16 @@ public class ActivityTimeTracker implements ActivityVisitor{ public ActivityTimeTracker(ForwardTransportTime transportTime) { super(); this.transportTime = transportTime; - this.startStrategy = new ActivityStartsAsSoonAsTimeWindowOpens(); + this.startStrategy = new ActivityStartsAsSoonAsNextTimeWindowOpens(); } public ActivityTimeTracker(ForwardTransportTime transportTime, ActivityPolicy activityPolicy) { super(); this.transportTime = transportTime; if(activityPolicy.equals(ActivityPolicy.AS_SOON_AS_ARRIVED)){ - this.startStrategy = new ActivityStartsAsSoonAsTimeWindowOpens(); + this.startStrategy = new ActivityStartAsSoonAsArrived(); } - else this.startStrategy = new ActivityStartAsSoonAsArrived(); + else this.startStrategy = new ActivityStartsAsSoonAsNextTimeWindowOpens(); } public ActivityTimeTracker(ForwardTransportTime transportTime, ActivityStartStrategy startStrategy) { @@ -79,7 +79,8 @@ public class ActivityTimeTracker implements ActivityVisitor{ @Override public void begin(VehicleRoute route) { - prevAct = route.getStart(); + prevAct = route.getStart(); +// System.out.println(prevAct); startAtPrevAct = prevAct.getEndTime(); actEndTime = startAtPrevAct; this.route = route; @@ -92,6 +93,11 @@ public class ActivityTimeTracker implements ActivityVisitor{ double transportTime = this.transportTime.getTransportTime(prevAct.getLocation(), activity.getLocation(), startAtPrevAct, route.getDriver(), route.getVehicle()); double arrivalTimeAtCurrAct = startAtPrevAct + transportTime; actArrTime = arrivalTimeAtCurrAct; +// System.out.println("oldArrTime: " + activity.getArrTime()); +// System.out.println(actArrTime + " " + activity + " tws: " + activity.getTimeWindows().toString()); + + assert actArrTime <= activity.getTimeWindows().get(activity.getTimeWindows().size()-1).getEnd() : "that should not be"; + double operationEndTime = startStrategy.getActivityStartTime(activity,arrivalTimeAtCurrAct) + activity.getOperationTime(); actEndTime = operationEndTime; prevAct = activity; @@ -103,6 +109,10 @@ public class ActivityTimeTracker implements ActivityVisitor{ double transportTime = this.transportTime.getTransportTime(prevAct.getLocation(), route.getEnd().getLocation(), startAtPrevAct, route.getDriver(), route.getVehicle()); double arrivalTimeAtCurrAct = startAtPrevAct + transportTime; actArrTime = arrivalTimeAtCurrAct; + +// System.out.println("end arr time: " + actArrTime); + assert actArrTime <= route.getVehicle().getLatestArrival() : "oohh. this should not be"; + actEndTime = arrivalTimeAtCurrAct; beginFirst = false; } diff --git a/jsprit-core/src/main/java/jsprit/core/util/CalculationUtils.java b/jsprit-core/src/main/java/jsprit/core/util/CalculationUtils.java index a00b40d6..de5a6a3a 100644 --- a/jsprit-core/src/main/java/jsprit/core/util/CalculationUtils.java +++ b/jsprit-core/src/main/java/jsprit/core/util/CalculationUtils.java @@ -18,6 +18,7 @@ package jsprit.core.util; +import jsprit.core.algorithm.state.ActivityStartsAsSoonAsNextTimeWindowOpens; import jsprit.core.problem.solution.route.activity.TourActivity; public class CalculationUtils { @@ -31,6 +32,7 @@ public class CalculationUtils { * @return */ public static double getActivityEndTime(double actArrTime, TourActivity act){ - return Math.max(actArrTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime(); + return new ActivityStartsAsSoonAsNextTimeWindowOpens().getActivityStartTime(act,actArrTime) + act.getOperationTime(); +// return Math.max(actArrTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime(); } } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/state/GetLatestArrivalTimeTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/state/GetLatestArrivalTimeTest.java index a3b3379a..3f0bf65c 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/state/GetLatestArrivalTimeTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/state/GetLatestArrivalTimeTest.java @@ -6,6 +6,7 @@ import org.junit.Test; import java.util.Arrays; import java.util.Collection; +import java.util.List; /** * Created by schroeder on 08/07/15. @@ -65,6 +66,30 @@ public class GetLatestArrivalTimeTest { Assert.assertEquals(1.,getLatestArrivalTime(Arrays.asList(tw,tw2),1)); } + @Test + public void whenMultiple3TW1_itShouldReturnCorrectTime(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw2 = TimeWindow.newInstance(20,30); + TimeWindow tw3 = TimeWindow.newInstance(40,50); + Assert.assertEquals(30.,getLatestArrivalTime(Arrays.asList(tw,tw2,tw3),35)); + } + + @Test + public void whenMultiple3TW2_itShouldReturnCorrectTime(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw2 = TimeWindow.newInstance(20,30); + TimeWindow tw3 = TimeWindow.newInstance(40,50); + Assert.assertEquals(50.,getLatestArrivalTime(Arrays.asList(tw,tw2,tw3),55)); + } + + @Test + public void whenMultiple3TW3_itShouldReturnCorrectTime(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw2 = TimeWindow.newInstance(20,30); + TimeWindow tw3 = TimeWindow.newInstance(40,50); + Assert.assertEquals(45.,getLatestArrivalTime(Arrays.asList(tw,tw2,tw3),45)); + } + @Test public void whenSingleTW_ActivityStartTime_shouldReturnCorrectTime(){ TimeWindow tw = TimeWindow.newInstance(2,10); @@ -118,6 +143,31 @@ public class GetLatestArrivalTimeTest { Assert.assertEquals(31.,getActivityStartTime(Arrays.asList(tw,tw2),31)); } + @Test + public void whenMultiple3TW1_ActivityStartTime_shouldReturnCorrectTime(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw2 = TimeWindow.newInstance(20,30); + TimeWindow tw3 = TimeWindow.newInstance(40,80); + Assert.assertEquals(40.,getActivityStartTime(Arrays.asList(tw,tw2,tw3),31)); + } + + @Test + public void whenMultiple3TW2_ActivityStartTime_shouldReturnCorrectTime(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw2 = TimeWindow.newInstance(20,30); + TimeWindow tw3 = TimeWindow.newInstance(40,80); + Assert.assertEquals(90.,getActivityStartTime(Arrays.asList(tw,tw2,tw3),90)); + } + + @Test + public void whenMultiple4TW1_ActivityStartTime_shouldReturnCorrectTime(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw2 = TimeWindow.newInstance(20,30); + TimeWindow tw3 = TimeWindow.newInstance(40,80); + TimeWindow tw4 = TimeWindow.newInstance(140,180); + Assert.assertEquals(140.,getActivityStartTime(Arrays.asList(tw,tw2,tw3,tw4),130)); + } + private double getLatestArrivalTime(Collection timeWindows, double potentialLatestArrivalTimeAtCurrAct) { TimeWindow last = null; for(TimeWindow tw : timeWindows){ @@ -135,23 +185,51 @@ public class GetLatestArrivalTimeTest { return last.getEnd(); } - private double getActivityStartTime(Collection timeWindows, double arrivalTime) { - boolean next = false; - for(TimeWindow tw : timeWindows){ - if(next){ - return Math.max(tw.getStart(),arrivalTime); - } + private double getActivityStartTime(List timeWindows, double arrivalTime) { + TimeWindow last = null; + for(int i=timeWindows.size()-1; i >= 0; i--){ + TimeWindow tw = timeWindows.get(i); if(tw.getStart() <= arrivalTime && tw.getEnd() >= arrivalTime){ return arrivalTime; } - else if(tw.getEnd() < arrivalTime){ - next = true; + else if(arrivalTime > tw.getEnd()){ + if(last != null) return last.getStart(); + else return arrivalTime; } - else if(tw.getStart() > arrivalTime){ - return tw.getStart(); + last = tw; + } + return Math.max(arrivalTime,last.getStart()); + } + + @Test + public void singleTWshouldWork(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + Assert.assertEquals(tw,getNextTimeWindow(11, Arrays.asList(tw))); + } + + @Test + public void multipleTWshouldWork(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw1 = TimeWindow.newInstance(20,30); + Assert.assertEquals(tw1,getNextTimeWindow(19,Arrays.asList(tw,tw1))); + } + + @Test + public void multipleTW2shouldWork(){ + TimeWindow tw = TimeWindow.newInstance(2,10); + TimeWindow tw1 = TimeWindow.newInstance(20,30); + TimeWindow tw2 = TimeWindow.newInstance(40,50); + Assert.assertEquals(tw2,getNextTimeWindow(31,Arrays.asList(tw,tw1,tw2))); + } + + private TimeWindow getNextTimeWindow(double actArrTime, Collection timeWindows) { + for(TimeWindow tw : timeWindows){ + if(actArrTime >= tw.getStart() && actArrTime <= tw.getEnd()) return tw; + else if(actArrTime < tw.getStart()){ + return tw; } } - return arrivalTime; + return null; } } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateVehicleDependentTimeWindowTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateVehicleDependentTimeWindowTest.java index 756f63dc..7bc3ca14 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateVehicleDependentTimeWindowTest.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateVehicleDependentTimeWindowTest.java @@ -179,7 +179,40 @@ public class UpdateVehicleDependentTimeWindowTest { } + @Test + public void twUpdateShouldWorkWithMultipleTWs(){ + // + VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("0,0")).setEarliestStart(0.).setLatestArrival(100.).build(); + Service service = Service.Builder.newInstance("s1").setLocation(Location.newInstance("10,0")) + .addTimeWindow(10,20).addTimeWindow(30,40).build(); + Service service2 = Service.Builder.newInstance("s2") + .addTimeWindow(20,30).addTimeWindow(40,60).addTimeWindow(70,80).setLocation(Location.newInstance("20,0")).build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(service).addJob(service2).addVehicle(vehicle) + .setRoutingCost(routingCosts).build(); + + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle).setJobActivityFactory(vrp.getJobActivityFactory()) + .addService(service).addService(service2).build(); + + StateManager stateManager = new StateManager(vrp); + UpdateVehicleDependentPracticalTimeWindows updater = new UpdateVehicleDependentPracticalTimeWindows(stateManager,routingCosts); + updater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() { + + @Override + public Collection get(VehicleRoute route) { + Collection vehicles = new ArrayList(); + vehicles.add(route.getVehicle()); +// vehicles.addAll(fleetManager.getAvailableVehicles(route.getVehicle())); + return vehicles; + } + + }); + stateManager.addStateUpdater(updater); + stateManager.informInsertionStarts(Arrays.asList(route), Collections.emptyList()); + + assertEquals(80.,stateManager.getActivityState(route.getActivities().get(1),vehicle, + InternalStates.LATEST_OPERATION_START_TIME, Double.class),0.01); + } } diff --git a/jsprit-core/src/test/resources/infiniteWriterV2Test.xml b/jsprit-core/src/test/resources/infiniteWriterV2Test.xml index 07c5406a..2d9058ab 100644 --- a/jsprit-core/src/test/resources/infiniteWriterV2Test.xml +++ b/jsprit-core/src/test/resources/infiniteWriterV2Test.xml @@ -2,24 +2,9 @@ - FINITE + INFINITE - - v2 - vehType2 - - loc - - - loc - - - 0.0 - 1.7976931348623157E308 - - true - v1 vehType @@ -48,16 +33,58 @@ - - vehType2 - - 200 - - - 0.0 - 1.0 - - - + + + + loc + + + 1 + + 2.0 + + + 0.0 + 1.7976931348623157E308 + + + + + + loc2 + + + 1 + + 4.0 + + + 0.0 + 1.7976931348623157E308 + + + + + + + 10.0 + + + noDriver + v1 + 0.0 + + 1 + 0.0 + 0.0 + + 0.0 + + + + + + + diff --git a/jsprit-instances/src/main/java/jsprit/instance/reader/BelhaizaReader.java b/jsprit-instances/src/main/java/jsprit/instance/reader/BelhaizaReader.java index 14deb7f8..95deb5b4 100644 --- a/jsprit-instances/src/main/java/jsprit/instance/reader/BelhaizaReader.java +++ b/jsprit-instances/src/main/java/jsprit/instance/reader/BelhaizaReader.java @@ -98,7 +98,7 @@ public class BelhaizaReader { typeBuilder.setCostPerDistance(1.0*variableCostProjectionFactor).setFixedCost(fixedCostPerVehicle); VehicleTypeImpl vehicleType = typeBuilder.build(); double end = Double.parseDouble(tokens[8])*timeProjectionFactor; - for(int i=0;i<11;i++) { + for(int i=0;i<10;i++) { VehicleImpl vehicle = VehicleImpl.Builder.newInstance("solomonVehicle"+(i+1)).setEarliestStart(0.).setLatestArrival(end) .setStartLocation(Location.Builder.newInstance().setId(customerId) .setCoordinate(coord).build()).setType(vehicleType).build();