From 926f7c2bfeab264070583c9b867e9046deaad019 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Fri, 17 Mar 2023 17:17:49 +0100 Subject: [PATCH 01/12] fixed approach time for drt dropoffs --- .../edrt/run/EDrtModeOptimizerQSimModule.java | 2 +- .../run/ShiftDrtModeOptimizerQSimModule.java | 2 +- .../optimizer/DrtModeOptimizerQSimModule.java | 2 +- .../DefaultInsertionCostCalculator.java | 24 ++++++++++++++++++- .../contrib/drt/run/DrtConfigGroup.java | 9 +++++++ .../InsertionCostCalculatorTest.java | 3 ++- 6 files changed, 37 insertions(+), 5 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java index 7e3737978ef..80a20bbda5d 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java @@ -132,7 +132,7 @@ public EmptyVehicleChargingScheduler get() { getter.getModal(QSimScopeForkJoinPoolHolder.class).getPool()))).asEagerSingleton(); bindModal(InsertionCostCalculator.class).toProvider(modalProvider( - getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class)))); + getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), drtCfg))); install(DrtModeOptimizerQSimModule.getInsertionSearchQSimModule(drtCfg)); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java index cb23ac6aa6e..945e1ecc7ca 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java @@ -117,7 +117,7 @@ shiftsParams, new DefaultShiftStartLogic(), new DefaultAssignShiftToVehicleLogic bindModal(InsertionCostCalculator.class).toProvider(modalProvider( getter -> new ShiftInsertionCostCalculator(getter.get(MobsimTimer.class), - new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class))))); + new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), drtCfg)))); bindModal(VehicleEntry.EntryFactory.class).toInstance(new ShiftVehicleDataEntryFactory(new VehicleDataEntryFactoryImpl(drtCfg))); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java index 57744a798df..87202ab195a 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java @@ -100,7 +100,7 @@ protected void configureQSim() { getter.getModal(QSimScopeForkJoinPoolHolder.class).getPool()))).asEagerSingleton(); bindModal(InsertionCostCalculator.class).toProvider(modalProvider( - getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class)))); + getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), drtCfg))); install(getInsertionSearchQSimModule(drtCfg)); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index 849d2dc02c4..3a28a47d65c 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -21,17 +21,22 @@ import static org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator.Insertion; +import org.matsim.contrib.drt.optimizer.Waypoint; import org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.DetourTimeInfo; import org.matsim.contrib.drt.passenger.DrtRequest; +import org.matsim.contrib.drt.run.DrtConfigGroup; /** * @author michalm */ public class DefaultInsertionCostCalculator implements InsertionCostCalculator { private final CostCalculationStrategy costCalculationStrategy; + private final DrtConfigGroup drtConfigGroup; - public DefaultInsertionCostCalculator(CostCalculationStrategy costCalculationStrategy) { + public DefaultInsertionCostCalculator(CostCalculationStrategy costCalculationStrategy, + DrtConfigGroup drtConfigGroup) { this.costCalculationStrategy = costCalculationStrategy; + this.drtConfigGroup = drtConfigGroup; } /** @@ -55,6 +60,23 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn return INFEASIBLE_SOLUTION_COST; } + // divert right now + if(insertion.pickup.index == 0) { + Waypoint nextWaypoint = insertion.pickup.nextWaypoint; + // there is an existing stop following the new insertion + if(nextWaypoint instanceof Waypoint.Stop && nextWaypoint != insertion.pickup.newWaypoint) { + // passengers are being dropped off == may be close to arrival + if(!((Waypoint.Stop) nextWaypoint).task.getDropoffRequests().isEmpty()) { + double nextArrival = nextWaypoint.getArrivalTime(); + double departureTime = insertion.vehicleEntry.start.getDepartureTime(); + //arrival is very soon + if (nextArrival - departureTime < drtConfigGroup.fixedApproachTime) { + return INFEASIBLE_SOLUTION_COST; + } + } + } + } + return costCalculationStrategy.calcCost(drtRequest, insertion, detourTimeInfo); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 1de8257baf3..5687b53ef63 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -184,6 +184,15 @@ public enum OperationalScheme { @PositiveOrZero public double advanceRequestPlanningHorizon = 0; // beta-feature; planning horizon for advance (prebooked) requests + @Parameter + @Comment( + "Time before reaching a planned dropoff from which it is not allowed to insert new detours for new requests. I.e.," + + " if set to 180, then a vehicle will not divert to pickup a new passenger once a boarded passenger is only " + + "3 minutes away from her destination, even though her time window would allow it." + + " Delayed detour just before arrival are usually perceived very negatively.") + @PositiveOrZero // used only for stopbased DRT scheme + public double fixedApproachTime = 0;// [m]; + @NotNull private DrtInsertionSearchParams drtInsertionSearchParams; diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java index 22af2a9cf15..e5a22f5ee90 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java @@ -30,6 +30,7 @@ import org.matsim.contrib.drt.optimizer.VehicleEntry; import org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator.Insertion; import org.matsim.contrib.drt.passenger.DrtRequest; +import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.testcases.fakes.FakeLink; /** @@ -64,7 +65,7 @@ public void testCalculate() { private void assertCalculate(Insertion insertion, DetourTimeInfo detourTimeInfo, double expectedCost) { var insertionCostCalculator = new DefaultInsertionCostCalculator( - new CostCalculationStrategy.RejectSoftConstraintViolations()); + new CostCalculationStrategy.RejectSoftConstraintViolations(), new DrtConfigGroup()); var insertionWithDetourData = new InsertionWithDetourData(insertion, null, detourTimeInfo); assertThat(insertionCostCalculator.calculate(drtRequest, insertionWithDetourData.insertion, insertionWithDetourData.detourTimeInfo)).isEqualTo(expectedCost); From 578f7672e22e1460f6dee8a0941cb6f9b63e3a9e Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sat, 25 Mar 2023 12:43:20 +0100 Subject: [PATCH 02/12] allowDetourBeforeArrivalThreshold --- .../DefaultInsertionCostCalculator.java | 31 ++++++++++--------- .../contrib/drt/run/DrtConfigGroup.java | 6 ++-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index 3a28a47d65c..77211ae5c3f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -60,23 +60,26 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn return INFEASIBLE_SOLUTION_COST; } - // divert right now - if(insertion.pickup.index == 0) { - Waypoint nextWaypoint = insertion.pickup.nextWaypoint; - // there is an existing stop following the new insertion - if(nextWaypoint instanceof Waypoint.Stop && nextWaypoint != insertion.pickup.newWaypoint) { - // passengers are being dropped off == may be close to arrival - if(!((Waypoint.Stop) nextWaypoint).task.getDropoffRequests().isEmpty()) { - double nextArrival = nextWaypoint.getArrivalTime(); - double departureTime = insertion.vehicleEntry.start.getDepartureTime(); - //arrival is very soon - if (nextArrival - departureTime < drtConfigGroup.fixedApproachTime) { - return INFEASIBLE_SOLUTION_COST; - } + // all stops after the new (potential) pickup but before the new dropoff + // are delayed by pickupDetourTimeLoss + double detour = detourTimeInfo.pickupDetourInfo.pickupTimeLoss; + for (int s = insertion.pickup.index; s < vEntry.stops.size(); s++) { + Waypoint.Stop stop = vEntry.stops.get(s); + // passengers are being dropped off == may be close to arrival + if(!stop.task.getDropoffRequests().isEmpty()) { + double nextArrival = stop.getArrivalTime(); + double departureTime = insertion.vehicleEntry.start.getDepartureTime(); + //arrival is very soon + if (nextArrival - departureTime < drtConfigGroup.allowDetourBeforeArrivalThreshold && + detour > 0) { + return INFEASIBLE_SOLUTION_COST; } } + if(s == insertion.dropoff.index) { + // all stops after the new (potential) dropoff are delayed by totalTimeLoss + detour = detourTimeInfo.getTotalTimeLoss(); + } } - return costCalculationStrategy.calcCost(drtRequest, insertion, detourTimeInfo); } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 5687b53ef63..279e6706d2f 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -187,11 +187,11 @@ public enum OperationalScheme { @Parameter @Comment( "Time before reaching a planned dropoff from which it is not allowed to insert new detours for new requests. I.e.," + - " if set to 180, then a vehicle will not divert to pickup a new passenger once a boarded passenger is only " + + " if set to 180, then a vehicle will not divert to pickup or dropoff a new passenger once a boarded passenger is only " + "3 minutes away from her destination, even though her time window would allow it." + - " Delayed detour just before arrival are usually perceived very negatively.") + " Delayed detours just before arrival are usually perceived very negatively.") @PositiveOrZero // used only for stopbased DRT scheme - public double fixedApproachTime = 0;// [m]; + public double allowDetourBeforeArrivalThreshold = 0;// [m]; @NotNull private DrtInsertionSearchParams drtInsertionSearchParams; From eb1b9afbeaa23ce6e56a4c0cfbe276b48935d5ae Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sat, 25 Mar 2023 12:48:23 +0100 Subject: [PATCH 03/12] break early when following stops are above the threshold --- .../optimizer/insertion/DefaultInsertionCostCalculator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index 77211ae5c3f..748c16fb024 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -73,6 +73,9 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn if (nextArrival - departureTime < drtConfigGroup.allowDetourBeforeArrivalThreshold && detour > 0) { return INFEASIBLE_SOLUTION_COST; + } else { + // all following stops are above the threshold + break; } } if(s == insertion.dropoff.index) { From 6a1ae2723cc55e8d20d86197eb3974cc3ecee9e2 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sat, 25 Mar 2023 12:54:30 +0100 Subject: [PATCH 04/12] catch case when there are no scheduled stops --- .../DefaultInsertionCostCalculator.java | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index 748c16fb024..c60ed6ab03e 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -63,26 +63,29 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn // all stops after the new (potential) pickup but before the new dropoff // are delayed by pickupDetourTimeLoss double detour = detourTimeInfo.pickupDetourInfo.pickupTimeLoss; - for (int s = insertion.pickup.index; s < vEntry.stops.size(); s++) { - Waypoint.Stop stop = vEntry.stops.get(s); - // passengers are being dropped off == may be close to arrival - if(!stop.task.getDropoffRequests().isEmpty()) { - double nextArrival = stop.getArrivalTime(); - double departureTime = insertion.vehicleEntry.start.getDepartureTime(); - //arrival is very soon - if (nextArrival - departureTime < drtConfigGroup.allowDetourBeforeArrivalThreshold && - detour > 0) { - return INFEASIBLE_SOLUTION_COST; - } else { - // all following stops are above the threshold - break; + if(!vEntry.stops.isEmpty()) { + for (int s = insertion.pickup.index; s < vEntry.stops.size(); s++) { + Waypoint.Stop stop = vEntry.stops.get(s); + // passengers are being dropped off == may be close to arrival + if (!stop.task.getDropoffRequests().isEmpty()) { + double nextArrival = stop.getArrivalTime(); + double departureTime = insertion.vehicleEntry.start.getDepartureTime(); + //arrival is very soon + if (nextArrival - departureTime < drtConfigGroup.allowDetourBeforeArrivalThreshold && + detour > 0) { + return INFEASIBLE_SOLUTION_COST; + } else { + // all following stops are above the threshold + break; + } + } + if (s == insertion.dropoff.index) { + // all stops after the new (potential) dropoff are delayed by totalTimeLoss + detour = detourTimeInfo.getTotalTimeLoss(); } - } - if(s == insertion.dropoff.index) { - // all stops after the new (potential) dropoff are delayed by totalTimeLoss - detour = detourTimeInfo.getTotalTimeLoss(); } } + return costCalculationStrategy.calcCost(drtRequest, insertion, detourTimeInfo); } } From d9e87224ece74dedbcecf4b6e506d514e995b32c Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sat, 25 Mar 2023 13:01:17 +0100 Subject: [PATCH 05/12] minor config updates --- .../main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index 279e6706d2f..1d50752aabd 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -190,8 +190,8 @@ public enum OperationalScheme { " if set to 180, then a vehicle will not divert to pickup or dropoff a new passenger once a boarded passenger is only " + "3 minutes away from her destination, even though her time window would allow it." + " Delayed detours just before arrival are usually perceived very negatively.") - @PositiveOrZero // used only for stopbased DRT scheme - public double allowDetourBeforeArrivalThreshold = 0;// [m]; + @PositiveOrZero + public double allowDetourBeforeArrivalThreshold = 0; // [s]; @NotNull private DrtInsertionSearchParams drtInsertionSearchParams; From 5550de965419ef6fd087512c60394051e412e974 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sat, 25 Mar 2023 13:37:52 +0100 Subject: [PATCH 06/12] fix bug --- .../drt/optimizer/insertion/DefaultInsertionCostCalculator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index c60ed6ab03e..83578d040fc 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -63,7 +63,7 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn // all stops after the new (potential) pickup but before the new dropoff // are delayed by pickupDetourTimeLoss double detour = detourTimeInfo.pickupDetourInfo.pickupTimeLoss; - if(!vEntry.stops.isEmpty()) { + if(vEntry.stops != null) { for (int s = insertion.pickup.index; s < vEntry.stops.size(); s++) { Waypoint.Stop stop = vEntry.stops.get(s); // passengers are being dropped off == may be close to arrival From 52e411c8c8cde297b97186c09d1bca4e48116dce Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 27 Mar 2023 16:54:31 +0200 Subject: [PATCH 07/12] add test for late detour prohibition --- .../InsertionCostCalculatorTest.java | 74 ++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java index e5a22f5ee90..ff108d70be7 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java @@ -24,13 +24,18 @@ import static org.matsim.contrib.drt.optimizer.insertion.InsertionCostCalculator.INFEASIBLE_SOLUTION_COST; import static org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.*; +import com.google.common.collect.ImmutableList; import org.junit.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.drt.optimizer.VehicleEntry; +import org.matsim.contrib.drt.optimizer.Waypoint; import org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator.Insertion; +import org.matsim.contrib.drt.passenger.AcceptedDrtRequest; import org.matsim.contrib.drt.passenger.DrtRequest; import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.schedule.DefaultDrtStopTask; +import org.matsim.contrib.drt.schedule.DrtStopTask; import org.matsim.testcases.fakes.FakeLink; /** @@ -43,36 +48,87 @@ public class InsertionCostCalculatorTest { @Test public void testCalculate() { - VehicleEntry entry = entry(new double[] { 20, 50 }); + VehicleEntry entry = entry(new double[] { 20, 50 }, null, null); var insertion = insertion(entry, 0, 1); //feasible solution assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 11), new DropoffDetourInfo(0, 22)), - 11 + 22); + 11 + 22, new DrtConfigGroup(), drtRequest); //feasible solution - longest possible pickup and dropoff time losses assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 20), new DropoffDetourInfo(0, 30)), - 20 + 30); + 20 + 30, new DrtConfigGroup(), drtRequest); //infeasible solution - time constraints at stop 0 assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 21), new DropoffDetourInfo(0, 29)), - INFEASIBLE_SOLUTION_COST); + INFEASIBLE_SOLUTION_COST, new DrtConfigGroup(), drtRequest); //infeasible solution - vehicle time constraints assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 20), new DropoffDetourInfo(0, 31)), - INFEASIBLE_SOLUTION_COST); + INFEASIBLE_SOLUTION_COST, new DrtConfigGroup(), drtRequest); } - private void assertCalculate(Insertion insertion, DetourTimeInfo detourTimeInfo, double expectedCost) { + + @Test + public void testAllowDetourBeforeArrivalThreshold() { + + + // start (0s) -----> new PU (60s) -----> existing DO (120s) -----> new DO (300s) + + Waypoint.Start start = new Waypoint.Start(null, link("start"), 0, 0); + + DrtStopTask existingDropoffTask = new DefaultDrtStopTask(120, 150, link("boardedDO")); + DrtRequest boardedRequest = DrtRequest.newBuilder().fromLink(link("boardedFrom")).toLink(link("boardedTo")).build(); + + AcceptedDrtRequest existingRequest = AcceptedDrtRequest.createFromOriginalRequest(boardedRequest); + existingDropoffTask.addDropoffRequest(existingRequest); + + Waypoint.Stop[] stops = new Waypoint.Stop[1]; + stops[0] = new Waypoint.Stop(existingDropoffTask, 0); + + VehicleEntry entry = entry(new double[] {60, 300}, ImmutableList.copyOf(stops), start); + var insertion = insertion(entry, 0, 1); + + DrtRequest drtRequest = DrtRequest.newBuilder() + .fromLink(fromLink) + .toLink(toLink) + .latestStartTime(120) + .latestArrivalTime(300) + .build(); + + DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); + + // new insertion before dropoff of boarded passenger within threshold - infeasible solution + drtConfigGroup.allowDetourBeforeArrivalThreshold = 180; + assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), + INFEASIBLE_SOLUTION_COST, drtConfigGroup, drtRequest); + + // new insertion before dropoff of boarded passenger, inside of threshold but no additional delay - feasible solution + assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(120, 0), new DropoffDetourInfo(300, 30)), + 30, drtConfigGroup, drtRequest); + + // new insertion before dropoff of boarded passenger, but outside of threshold - feasible solution + drtConfigGroup.allowDetourBeforeArrivalThreshold = 120; + assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), + 60, drtConfigGroup, drtRequest); + + + // new insertion after dropoff of boarded passenger - feasible solution + insertion = insertion(entry, 1, 1); + assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), + 60, drtConfigGroup, drtRequest); + } + + private void assertCalculate(Insertion insertion, DetourTimeInfo detourTimeInfo, double expectedCost, DrtConfigGroup drtConfigGroup, DrtRequest drtRequest) { var insertionCostCalculator = new DefaultInsertionCostCalculator( - new CostCalculationStrategy.RejectSoftConstraintViolations(), new DrtConfigGroup()); + new CostCalculationStrategy.RejectSoftConstraintViolations(), drtConfigGroup); var insertionWithDetourData = new InsertionWithDetourData(insertion, null, detourTimeInfo); assertThat(insertionCostCalculator.calculate(drtRequest, insertionWithDetourData.insertion, insertionWithDetourData.detourTimeInfo)).isEqualTo(expectedCost); } - private VehicleEntry entry(double[] slackTimes) { - return new VehicleEntry(null, null, null, slackTimes); + private VehicleEntry entry(double[] slackTimes, ImmutableList stops, Waypoint.Start start) { + return new VehicleEntry(null, start, stops, slackTimes); } private Link link(String id) { From 3ade88e89f8134133f172c52b4dde2d63645f470 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 28 Mar 2023 17:36:39 +0200 Subject: [PATCH 08/12] add one more test --- .../InsertionCostCalculatorTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java index ff108d70be7..9701ce65db1 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java @@ -119,6 +119,52 @@ public void testAllowDetourBeforeArrivalThreshold() { 60, drtConfigGroup, drtRequest); } + @Test + public void testAllowDetourBeforeArrivalThreshold2() { + + // start (0s) -----> new PU (60s) -----> existing PU (120s) -----> existing DO (200s) -----> new DO (300s) + + Waypoint.Start start = new Waypoint.Start(null, link("start"), 0, 0); + + DrtStopTask existingPickupTask = new DefaultDrtStopTask(120, 150, link("scheduledPU")); + DrtRequest scheduledRequest = DrtRequest.newBuilder().fromLink(link("scheduledFrom")).toLink(link("scheduledTo")).build(); + AcceptedDrtRequest acceptedScheduledRequest = AcceptedDrtRequest.createFromOriginalRequest(scheduledRequest); + existingPickupTask.addPickupRequest(acceptedScheduledRequest); + + DrtStopTask existingDropoffTask = new DefaultDrtStopTask(200, 230, link("boardedDO")); + DrtRequest boardedRequest = DrtRequest.newBuilder().fromLink(link("boardedFrom")).toLink(link("boardedTo")).build(); + AcceptedDrtRequest existingRequest = AcceptedDrtRequest.createFromOriginalRequest(boardedRequest); + existingDropoffTask.addDropoffRequest(existingRequest); + + Waypoint.Stop[] stops = new Waypoint.Stop[2]; + stops[0] = new Waypoint.Stop(existingPickupTask, 2); + stops[1] = new Waypoint.Stop(existingDropoffTask, 1); + + VehicleEntry entry = entry(new double[] {60, 60, 300}, ImmutableList.copyOf(stops), start); + + + var insertion = insertion(entry, 0, 2); + + DrtRequest drtRequest = DrtRequest.newBuilder() + .fromLink(fromLink) + .toLink(toLink) + .latestStartTime(120) + .latestArrivalTime(300) + .build(); + + DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); + + // new insertion before dropoff of boarded passenger within threshold - infeasible solution + drtConfigGroup.allowDetourBeforeArrivalThreshold = 300; + assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 60), new DropoffDetourInfo(300, 60)), + INFEASIBLE_SOLUTION_COST, drtConfigGroup, drtRequest); + + // new insertion before dropoff of boarded passenger outside of threshold - feasible solution + drtConfigGroup.allowDetourBeforeArrivalThreshold = 200; + assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 60), new DropoffDetourInfo(300, 60)), + 120, drtConfigGroup, drtRequest); + } + private void assertCalculate(Insertion insertion, DetourTimeInfo detourTimeInfo, double expectedCost, DrtConfigGroup drtConfigGroup, DrtRequest drtRequest) { var insertionCostCalculator = new DefaultInsertionCostCalculator( new CostCalculationStrategy.RejectSoftConstraintViolations(), drtConfigGroup); From 532d7e03dc7931522ae5888b45285b62d5c52bbf Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 27 May 2024 17:47:49 +0200 Subject: [PATCH 09/12] update detour before arrival threshold --- .../edrt/run/EDrtModeOptimizerQSimModule.java | 3 +- .../run/ShiftDrtModeOptimizerQSimModule.java | 3 +- .../optimizer/DrtModeOptimizerQSimModule.java | 3 +- .../DrtOptimizationConstraintsSet.java | 9 +++ .../DefaultInsertionCostCalculator.java | 14 ++--- .../contrib/drt/run/DrtConfigGroup.java | 9 --- .../InsertionCostCalculatorTest.java | 62 +++++++++++-------- 7 files changed, 58 insertions(+), 45 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java index 0a7537997c7..c888ff86d8d 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/edrt/run/EDrtModeOptimizerQSimModule.java @@ -134,7 +134,8 @@ public EmptyVehicleChargingScheduler get() { getter.getModal(PassengerStopDurationProvider.class)))).asEagerSingleton(); bindModal(InsertionCostCalculator.class).toProvider(modalProvider( - getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), drtCfg))); + getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), + drtCfg.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet()))); install(DrtModeOptimizerQSimModule.getInsertionSearchQSimModule(drtCfg)); diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java index d41ce503ef0..5fbae488eec 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java @@ -121,7 +121,8 @@ shiftsParams, new DefaultShiftStartLogic(), new DefaultAssignShiftToVehicleLogic bindModal(InsertionCostCalculator.class).toProvider(modalProvider( getter -> new ShiftInsertionCostCalculator(getter.get(MobsimTimer.class), - new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), drtCfg)))); + new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), + drtCfg.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet())))); bindModal(VehicleEntry.EntryFactory.class).toInstance(new ShiftVehicleDataEntryFactory(new VehicleDataEntryFactoryImpl())); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java index 3eb01298e71..9a930b9cdbf 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtModeOptimizerQSimModule.java @@ -110,7 +110,8 @@ protected void configureQSim() { getter.getModal(PassengerStopDurationProvider.class)))).asEagerSingleton(); bindModal(InsertionCostCalculator.class).toProvider(modalProvider( - getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), drtCfg))); + getter -> new DefaultInsertionCostCalculator(getter.getModal(CostCalculationStrategy.class), + drtCfg.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet()))); install(getInsertionSearchQSimModule(drtCfg)); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java index d80bc047b4e..9e7f63c4940 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java @@ -88,6 +88,15 @@ public DrtOptimizationConstraintsSet() { @PositiveOrZero // used only for stopbased DRT scheme public double maxWalkDistance = Double.MAX_VALUE;// [m]; + @Parameter + @Comment( + "Time before reaching a planned dropoff from which it is not allowed to insert new detours for new requests. I.e.," + + " if set to 180, then a vehicle will not divert to pickup or dropoff a new passenger once a boarded passenger is only " + + "3 minutes away from her destination, even though her time window would allow it." + + " Delayed detours just before arrival are usually perceived very negatively.") + @PositiveOrZero + public double allowDetourBeforeArrivalThreshold = 0; // [s]; + @Override protected void checkConsistency(Config config) { super.checkConsistency(config); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index b5c428f17b3..a44dc5d24ff 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -19,24 +19,24 @@ package org.matsim.contrib.drt.optimizer.insertion; -import static org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator.Insertion; - +import org.matsim.contrib.drt.optimizer.DrtOptimizationConstraintsSet; import org.matsim.contrib.drt.optimizer.Waypoint; import org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.DetourTimeInfo; import org.matsim.contrib.drt.passenger.DrtRequest; -import org.matsim.contrib.drt.run.DrtConfigGroup; + +import static org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator.Insertion; /** * @author michalm */ public class DefaultInsertionCostCalculator implements InsertionCostCalculator { private final CostCalculationStrategy costCalculationStrategy; - private final DrtConfigGroup drtConfigGroup; + private final DrtOptimizationConstraintsSet constraintsSet; public DefaultInsertionCostCalculator(CostCalculationStrategy costCalculationStrategy, - DrtConfigGroup drtConfigGroup) { + DrtOptimizationConstraintsSet constraintsSet) { this.costCalculationStrategy = costCalculationStrategy; - this.drtConfigGroup = drtConfigGroup; + this.constraintsSet = constraintsSet; } /** @@ -83,7 +83,7 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn double nextArrival = stop.getArrivalTime(); double departureTime = insertion.vehicleEntry.start.getDepartureTime(); //arrival is very soon - if (nextArrival - departureTime < drtConfigGroup.allowDetourBeforeArrivalThreshold && + if (nextArrival - departureTime < constraintsSet.allowDetourBeforeArrivalThreshold && detour > 0) { return INFEASIBLE_SOLUTION_COST; } else { diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java index d09f138687d..b271a8690e8 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/run/DrtConfigGroup.java @@ -158,15 +158,6 @@ public enum SimulationType { @Comment("Whether full simulation drt is employed") public SimulationType simulationType = SimulationType.fullSimulation; - @Parameter - @Comment( - "Time before reaching a planned dropoff from which it is not allowed to insert new detours for new requests. I.e.," + - " if set to 180, then a vehicle will not divert to pickup or dropoff a new passenger once a boarded passenger is only " + - "3 minutes away from her destination, even though her time window would allow it." + - " Delayed detours just before arrival are usually perceived very negatively.") - @PositiveOrZero - public double allowDetourBeforeArrivalThreshold = 0; // [s]; - @NotNull private DrtInsertionSearchParams drtInsertionSearchParams; diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java index 62c99e4d35a..206ed0b747d 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java @@ -20,17 +20,13 @@ package org.matsim.contrib.drt.optimizer.insertion; -import static org.assertj.core.api.Assertions.assertThat; -import static org.matsim.contrib.drt.optimizer.insertion.InsertionCostCalculator.INFEASIBLE_SOLUTION_COST; -import static org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.*; - import com.google.common.collect.ImmutableList; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.drt.optimizer.DrtOptimizationConstraintsSet; import org.matsim.contrib.drt.optimizer.VehicleEntry; import org.matsim.contrib.drt.optimizer.Waypoint; -import org.matsim.contrib.drt.optimizer.Waypoint; import org.matsim.contrib.drt.optimizer.insertion.InsertionGenerator.Insertion; import org.matsim.contrib.drt.passenger.AcceptedDrtRequest; import org.matsim.contrib.drt.passenger.DrtRequest; @@ -39,6 +35,12 @@ import org.matsim.contrib.drt.schedule.DrtStopTask; import org.matsim.testcases.fakes.FakeLink; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.matsim.contrib.drt.optimizer.insertion.InsertionCostCalculator.INFEASIBLE_SOLUTION_COST; +import static org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.*; + /** * @author Michal Maciejewski (michalm) */ @@ -49,24 +51,28 @@ public class InsertionCostCalculatorTest { @Test void testCalculate() { - VehicleEntry entry = entry(new double[] { 20, 20, 50 }, null, null); + VehicleEntry entry = entry(new double[] { 20, 20, 50 }, ImmutableList.builder().build(), null); var insertion = insertion(entry, 0, 1); //feasible solution + final DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 11), new DropoffDetourInfo(0, 22)), - 11 + 22, new DrtConfigGroup(), drtRequest); + 11 + 22, drtRequest, drtConfigGroup.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet()); //feasible solution - longest possible pickup and dropoff time losses + final DrtConfigGroup drtConfigGroup1 = new DrtConfigGroup(); assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 20), new DropoffDetourInfo(0, 30)), - 20 + 30, new DrtConfigGroup(), drtRequest); + 20 + 30, drtRequest, drtConfigGroup1.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet()); //infeasible solution - time constraints at stop 0 + final DrtConfigGroup drtConfigGroup2 = new DrtConfigGroup(); assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 21), new DropoffDetourInfo(0, 29)), - INFEASIBLE_SOLUTION_COST, new DrtConfigGroup(), drtRequest); + INFEASIBLE_SOLUTION_COST, drtRequest, drtConfigGroup2.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet()); //infeasible solution - vehicle time constraints + final DrtConfigGroup drtConfigGroup3 = new DrtConfigGroup(); assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(0, 20), new DropoffDetourInfo(0, 31)), - INFEASIBLE_SOLUTION_COST, new DrtConfigGroup(), drtRequest); + INFEASIBLE_SOLUTION_COST, drtRequest, drtConfigGroup3.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet()); } @@ -76,7 +82,7 @@ public void testAllowDetourBeforeArrivalThreshold() { // start (0s) -----> new PU (60s) -----> existing DO (120s) -----> new DO (300s) - Waypoint.Start start = new Waypoint.Start(null, link("start"), 0, 0); + Waypoint.Start start = new Waypoint.Start(null, link("start"), 0, 1); DrtStopTask existingDropoffTask = new DefaultDrtStopTask(120, 150, link("boardedDO")); DrtRequest boardedRequest = DrtRequest.newBuilder().fromLink(link("boardedFrom")).toLink(link("boardedTo")).build(); @@ -87,7 +93,7 @@ public void testAllowDetourBeforeArrivalThreshold() { Waypoint.Stop[] stops = new Waypoint.Stop[1]; stops[0] = new Waypoint.Stop(existingDropoffTask, 0); - VehicleEntry entry = entry(new double[] {60, 300}, ImmutableList.copyOf(stops), start); + VehicleEntry entry = entry(new double[] {60, 60, 300}, ImmutableList.copyOf(stops), start); var insertion = insertion(entry, 0, 1); DrtRequest drtRequest = DrtRequest.newBuilder() @@ -95,29 +101,31 @@ public void testAllowDetourBeforeArrivalThreshold() { .toLink(toLink) .latestStartTime(120) .latestArrivalTime(300) + .maxRideDuration(Double.MAX_VALUE) .build(); DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); + DrtOptimizationConstraintsSet drtOptimizationConstraintsSet = drtConfigGroup.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet(); // new insertion before dropoff of boarded passenger within threshold - infeasible solution - drtConfigGroup.allowDetourBeforeArrivalThreshold = 180; + drtOptimizationConstraintsSet.allowDetourBeforeArrivalThreshold = 180; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), - INFEASIBLE_SOLUTION_COST, drtConfigGroup, drtRequest); + INFEASIBLE_SOLUTION_COST, drtRequest, drtOptimizationConstraintsSet); // new insertion before dropoff of boarded passenger, inside of threshold but no additional delay - feasible solution assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(120, 0), new DropoffDetourInfo(300, 30)), - 30, drtConfigGroup, drtRequest); + 30, drtRequest, drtOptimizationConstraintsSet); // new insertion before dropoff of boarded passenger, but outside of threshold - feasible solution - drtConfigGroup.allowDetourBeforeArrivalThreshold = 120; + drtOptimizationConstraintsSet.allowDetourBeforeArrivalThreshold = 120; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), - 60, drtConfigGroup, drtRequest); + 60, drtRequest, drtOptimizationConstraintsSet); // new insertion after dropoff of boarded passenger - feasible solution insertion = insertion(entry, 1, 1); assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), - 60, drtConfigGroup, drtRequest); + 60, drtRequest, drtOptimizationConstraintsSet); } @Test @@ -141,7 +149,7 @@ public void testAllowDetourBeforeArrivalThreshold2() { stops[0] = new Waypoint.Stop(existingPickupTask, 2); stops[1] = new Waypoint.Stop(existingDropoffTask, 1); - VehicleEntry entry = entry(new double[] {60, 60, 300}, ImmutableList.copyOf(stops), start); + VehicleEntry entry = entry(new double[] {60, 60, 60, 300}, ImmutableList.copyOf(stops), start); var insertion = insertion(entry, 0, 2); @@ -151,31 +159,33 @@ public void testAllowDetourBeforeArrivalThreshold2() { .toLink(toLink) .latestStartTime(120) .latestArrivalTime(300) + .maxRideDuration(Double.MAX_VALUE) .build(); DrtConfigGroup drtConfigGroup = new DrtConfigGroup(); // new insertion before dropoff of boarded passenger within threshold - infeasible solution - drtConfigGroup.allowDetourBeforeArrivalThreshold = 300; + DrtOptimizationConstraintsSet constraintsSet = drtConfigGroup.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet(); + constraintsSet.allowDetourBeforeArrivalThreshold = 300; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 60), new DropoffDetourInfo(300, 60)), - INFEASIBLE_SOLUTION_COST, drtConfigGroup, drtRequest); + INFEASIBLE_SOLUTION_COST, drtRequest, constraintsSet); // new insertion before dropoff of boarded passenger outside of threshold - feasible solution - drtConfigGroup.allowDetourBeforeArrivalThreshold = 200; + constraintsSet.allowDetourBeforeArrivalThreshold = 200; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 60), new DropoffDetourInfo(300, 60)), - 120, drtConfigGroup, drtRequest); + 120, drtRequest, constraintsSet); } - private void assertCalculate(Insertion insertion, DetourTimeInfo detourTimeInfo, double expectedCost, DrtConfigGroup drtConfigGroup, DrtRequest drtRequest) { + private void assertCalculate(Insertion insertion, DetourTimeInfo detourTimeInfo, double expectedCost, DrtRequest drtRequest, DrtOptimizationConstraintsSet constraintsSet) { var insertionCostCalculator = new DefaultInsertionCostCalculator( - new CostCalculationStrategy.RejectSoftConstraintViolations(), drtConfigGroup); + new CostCalculationStrategy.RejectSoftConstraintViolations(), constraintsSet); var insertionWithDetourData = new InsertionWithDetourData(insertion, null, detourTimeInfo); assertThat(insertionCostCalculator.calculate(drtRequest, insertionWithDetourData.insertion, insertionWithDetourData.detourTimeInfo)).isEqualTo(expectedCost); } private VehicleEntry entry(double[] slackTimes, ImmutableList stops, Waypoint.Start start) { - return new VehicleEntry(null, start, stops, slackTimes, null, 0); + return new VehicleEntry(null, start, stops, slackTimes, stops.stream().map(s -> 0.).toList(), 0); } private Link link(String id) { From 3799804cf34409ec27c514a3c104eb40c511e214 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 27 May 2024 18:00:44 +0200 Subject: [PATCH 10/12] address review comments --- .../DefaultInsertionCostCalculator.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index a44dc5d24ff..14ec7ceb3d0 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -74,26 +74,31 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn // all stops after the new (potential) pickup but before the new dropoff // are delayed by pickupDetourTimeLoss - double detour = detourTimeInfo.pickupDetourInfo.pickupTimeLoss; + double timeLoss = detourTimeInfo.pickupDetourInfo.pickupTimeLoss; if(vEntry.stops != null) { for (int s = insertion.pickup.index; s < vEntry.stops.size(); s++) { + if(timeLoss == 0) { + continue; + } Waypoint.Stop stop = vEntry.stops.get(s); // passengers are being dropped off == may be close to arrival if (!stop.task.getDropoffRequests().isEmpty()) { double nextArrival = stop.getArrivalTime(); double departureTime = insertion.vehicleEntry.start.getDepartureTime(); - //arrival is very soon - if (nextArrival - departureTime < constraintsSet.allowDetourBeforeArrivalThreshold && - detour > 0) { + if (nextArrival - departureTime < constraintsSet.allowDetourBeforeArrivalThreshold) { + //arrival is too soon to allow further diversion return INFEASIBLE_SOLUTION_COST; - } else { + } else if (nextArrival - departureTime >= constraintsSet.allowDetourBeforeArrivalThreshold) { // all following stops are above the threshold break; } } if (s == insertion.dropoff.index) { // all stops after the new (potential) dropoff are delayed by totalTimeLoss - detour = detourTimeInfo.getTotalTimeLoss(); + timeLoss = detourTimeInfo.getTotalTimeLoss(); + if(timeLoss == 0) { + break; + } } } } From f029ca06cc5f8cb0359fbc0b404e35b1ecd60a77 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 27 May 2024 21:22:49 +0200 Subject: [PATCH 11/12] simplify method, rename to lateDiversionThreshold --- .../DrtOptimizationConstraintsSet.java | 2 +- .../DefaultInsertionCostCalculator.java | 65 ++++++++++--------- .../InsertionCostCalculatorTest.java | 10 ++- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java index 9e7f63c4940..63a03eaa014 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/DrtOptimizationConstraintsSet.java @@ -95,7 +95,7 @@ public DrtOptimizationConstraintsSet() { "3 minutes away from her destination, even though her time window would allow it." + " Delayed detours just before arrival are usually perceived very negatively.") @PositiveOrZero - public double allowDetourBeforeArrivalThreshold = 0; // [s]; + public double lateDiversionthreshold = 0; // [s]; @Override protected void checkConsistency(Config config) { diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index 14ec7ceb3d0..adbe51364c9 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -20,6 +20,7 @@ package org.matsim.contrib.drt.optimizer.insertion; import org.matsim.contrib.drt.optimizer.DrtOptimizationConstraintsSet; +import org.matsim.contrib.drt.optimizer.VehicleEntry; import org.matsim.contrib.drt.optimizer.Waypoint; import org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.DetourTimeInfo; import org.matsim.contrib.drt.passenger.DrtRequest; @@ -72,34 +73,9 @@ public double calculate(DrtRequest drtRequest, Insertion insertion, DetourTimeIn return INFEASIBLE_SOLUTION_COST; } - // all stops after the new (potential) pickup but before the new dropoff - // are delayed by pickupDetourTimeLoss - double timeLoss = detourTimeInfo.pickupDetourInfo.pickupTimeLoss; - if(vEntry.stops != null) { - for (int s = insertion.pickup.index; s < vEntry.stops.size(); s++) { - if(timeLoss == 0) { - continue; - } - Waypoint.Stop stop = vEntry.stops.get(s); - // passengers are being dropped off == may be close to arrival - if (!stop.task.getDropoffRequests().isEmpty()) { - double nextArrival = stop.getArrivalTime(); - double departureTime = insertion.vehicleEntry.start.getDepartureTime(); - if (nextArrival - departureTime < constraintsSet.allowDetourBeforeArrivalThreshold) { - //arrival is too soon to allow further diversion - return INFEASIBLE_SOLUTION_COST; - } else if (nextArrival - departureTime >= constraintsSet.allowDetourBeforeArrivalThreshold) { - // all following stops are above the threshold - break; - } - } - if (s == insertion.dropoff.index) { - // all stops after the new (potential) dropoff are delayed by totalTimeLoss - timeLoss = detourTimeInfo.getTotalTimeLoss(); - if(timeLoss == 0) { - break; - } - } + if (vEntry.stops != null && !vEntry.stops.isEmpty() && constraintsSet.lateDiversionthreshold > 0) { + if(violatesLateDiversion(insertion, detourTimeInfo, vEntry, effectiveDropoffTimeLoss)) { + return INFEASIBLE_SOLUTION_COST; } } @@ -111,4 +87,35 @@ private boolean violatesMaxRideDuration(DrtRequest drtRequest, InsertionDetourTi double rideDuration = detourTimeInfo.dropoffDetourInfo.arrivalTime - detourTimeInfo.pickupDetourInfo.departureTime; return drtRequest.getMaxRideDuration() < rideDuration; } -} + + private boolean violatesLateDiversion(Insertion insertion, DetourTimeInfo detourTimeInfo, + VehicleEntry vEntry, double effectiveDropoffTimeLoss) { + if (detourTimeInfo.pickupDetourInfo.pickupTimeLoss > 0) { + if (checkStopsForDetour(vEntry, insertion.pickup.index, insertion.dropoff.index, + constraintsSet.lateDiversionthreshold)) { + return true; + } + } + if (effectiveDropoffTimeLoss > 0) { + if (checkStopsForDetour(vEntry, insertion.dropoff.index, vEntry.stops.size(), + constraintsSet.lateDiversionthreshold)) { + return true; + } + } + return false; + } + + private boolean checkStopsForDetour(VehicleEntry vehicleEntry, int start, int end, double lateDiversionThreshold) { + for (int s = start; s < end; s++) { + Waypoint.Stop stop = vehicleEntry.stops.get(s); + if (!stop.task.getDropoffRequests().isEmpty()) { + double remainingRideDuration = stop.getArrivalTime() - vehicleEntry.start.getDepartureTime(); + if (remainingRideDuration < lateDiversionThreshold) { + return true; + } + break; + } + } + return false; + } +} \ No newline at end of file diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java index 206ed0b747d..8fab605b992 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/optimizer/insertion/InsertionCostCalculatorTest.java @@ -35,8 +35,6 @@ import org.matsim.contrib.drt.schedule.DrtStopTask; import org.matsim.testcases.fakes.FakeLink; -import java.util.Collections; - import static org.assertj.core.api.Assertions.assertThat; import static org.matsim.contrib.drt.optimizer.insertion.InsertionCostCalculator.INFEASIBLE_SOLUTION_COST; import static org.matsim.contrib.drt.optimizer.insertion.InsertionDetourTimeCalculator.*; @@ -108,7 +106,7 @@ public void testAllowDetourBeforeArrivalThreshold() { DrtOptimizationConstraintsSet drtOptimizationConstraintsSet = drtConfigGroup.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet(); // new insertion before dropoff of boarded passenger within threshold - infeasible solution - drtOptimizationConstraintsSet.allowDetourBeforeArrivalThreshold = 180; + drtOptimizationConstraintsSet.lateDiversionthreshold = 180; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), INFEASIBLE_SOLUTION_COST, drtRequest, drtOptimizationConstraintsSet); @@ -117,7 +115,7 @@ public void testAllowDetourBeforeArrivalThreshold() { 30, drtRequest, drtOptimizationConstraintsSet); // new insertion before dropoff of boarded passenger, but outside of threshold - feasible solution - drtOptimizationConstraintsSet.allowDetourBeforeArrivalThreshold = 120; + drtOptimizationConstraintsSet.lateDiversionthreshold = 120; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 30), new DropoffDetourInfo(300, 30)), 60, drtRequest, drtOptimizationConstraintsSet); @@ -166,12 +164,12 @@ public void testAllowDetourBeforeArrivalThreshold2() { // new insertion before dropoff of boarded passenger within threshold - infeasible solution DrtOptimizationConstraintsSet constraintsSet = drtConfigGroup.addOrGetDrtOptimizationConstraintsParams().addOrGetDefaultDrtOptimizationConstraintsSet(); - constraintsSet.allowDetourBeforeArrivalThreshold = 300; + constraintsSet.lateDiversionthreshold = 300; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 60), new DropoffDetourInfo(300, 60)), INFEASIBLE_SOLUTION_COST, drtRequest, constraintsSet); // new insertion before dropoff of boarded passenger outside of threshold - feasible solution - constraintsSet.allowDetourBeforeArrivalThreshold = 200; + constraintsSet.lateDiversionthreshold = 200; assertCalculate(insertion, new DetourTimeInfo(new PickupDetourInfo(60, 60), new DropoffDetourInfo(300, 60)), 120, drtRequest, constraintsSet); } From c81177c60195ec079c3d76c3e5e1a050176b7bac Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 27 May 2024 21:29:37 +0200 Subject: [PATCH 12/12] rename method --- .../optimizer/insertion/DefaultInsertionCostCalculator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java index adbe51364c9..f58acc13a27 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultInsertionCostCalculator.java @@ -91,13 +91,13 @@ private boolean violatesMaxRideDuration(DrtRequest drtRequest, InsertionDetourTi private boolean violatesLateDiversion(Insertion insertion, DetourTimeInfo detourTimeInfo, VehicleEntry vEntry, double effectiveDropoffTimeLoss) { if (detourTimeInfo.pickupDetourInfo.pickupTimeLoss > 0) { - if (checkStopsForDetour(vEntry, insertion.pickup.index, insertion.dropoff.index, + if (violatesLateDiversionBetweenStopIndices(vEntry, insertion.pickup.index, insertion.dropoff.index, constraintsSet.lateDiversionthreshold)) { return true; } } if (effectiveDropoffTimeLoss > 0) { - if (checkStopsForDetour(vEntry, insertion.dropoff.index, vEntry.stops.size(), + if (violatesLateDiversionBetweenStopIndices(vEntry, insertion.dropoff.index, vEntry.stops.size(), constraintsSet.lateDiversionthreshold)) { return true; } @@ -105,7 +105,7 @@ private boolean violatesLateDiversion(Insertion insertion, DetourTimeInfo detour return false; } - private boolean checkStopsForDetour(VehicleEntry vehicleEntry, int start, int end, double lateDiversionThreshold) { + private boolean violatesLateDiversionBetweenStopIndices(VehicleEntry vehicleEntry, int start, int end, double lateDiversionThreshold) { for (int s = start; s < end; s++) { Waypoint.Stop stop = vehicleEntry.stops.get(s); if (!stop.task.getDropoffRequests().isEmpty()) {