From 732f829e4238fac3f66080d2e2944666c9a129f7 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Tue, 5 Nov 2024 23:31:37 +0100 Subject: [PATCH] TEST: 145 - Add test for range raptor to ensure pareto optimal solutions are returned. --- .../raptor/router/RangeRaptorTest.java | 48 +++++++++++++++++++ .../router/RaptorRouterTestBuilder.java | 5 ++ 2 files changed, 53 insertions(+) diff --git a/src/test/java/ch/naviqore/raptor/router/RangeRaptorTest.java b/src/test/java/ch/naviqore/raptor/router/RangeRaptorTest.java index 299ce9f3..fd0d3785 100644 --- a/src/test/java/ch/naviqore/raptor/router/RangeRaptorTest.java +++ b/src/test/java/ch/naviqore/raptor/router/RangeRaptorTest.java @@ -18,6 +18,7 @@ public class RangeRaptorTest { private static final String STOP_A = "A"; private static final String STOP_I = "I"; + private static final String STOP_K = "K"; private static final String STOP_N = "N"; private static final LocalDateTime START_OF_DAY = LocalDateTime.of(2021, 1, 1, 0, 0); @@ -261,6 +262,53 @@ void findArrivalConnections_withSourceTransferFirst() { STOP_A, STOP_N); } + @Test + void ensureParetoOptimalConnections() { + // this test is based on a previous bug, where the range raptor router returned connections which were not + // pareto optimal (later arrival time and more rounds). This is owed to the fact that the range raptor spawns + // at different time points (range offsets) and potentially finds earliest arrival connections for the given + // offset with more rounds than the final best arrival time. + // this test reproduces this case by introducing a low frequency fast connection and a high frequency slower + // connection. + + int headwayRoute1 = 15; + int headwayRoute2 = 60; + int headwayRoute3and4 = 5; + + int dwellTime = 0; // simplification to better calculate times by hand + + RaptorAlgorithm rangeRaptor = new RaptorRouterTestBuilder().withAddRoute1_AG( + RaptorRouterTestBuilder.DEFAULT_OFFSET, headwayRoute1, + RaptorRouterTestBuilder.DEFAULT_TIME_BETWEEN_STOPS, dwellTime) + .withAddRoute2_HL(RaptorRouterTestBuilder.DEFAULT_OFFSET, headwayRoute2, + RaptorRouterTestBuilder.DEFAULT_TIME_BETWEEN_STOPS, dwellTime) + .withAddRoute3_MQ(RaptorRouterTestBuilder.DEFAULT_OFFSET, headwayRoute3and4, + RaptorRouterTestBuilder.DEFAULT_TIME_BETWEEN_STOPS, dwellTime) + .withAddRoute4_RS(RaptorRouterTestBuilder.DEFAULT_OFFSET, headwayRoute3and4, + RaptorRouterTestBuilder.DEFAULT_TIME_BETWEEN_STOPS, dwellTime) + .withSameStopTransferTime(0) + .withRaptorRange(900) // departures at 08:00 and 08:15 + .withMaxDaysToScan(1) + .build(); + + // departure at 8:00 will yield only one fastest connection + // 08:00 A --> R1 --> 08:05 B + // 08:05 B --> R2 --> 08:20 K + LocalDateTime expectedDepartureTime = EIGHT_AM; + LocalDateTime expectedArrivalTime = expectedDepartureTime.plusMinutes(20); + + // however since spawning at 08:15 (first range checked) will find following best solution, this test must + // ensure that this connection is not returned as it is not pareto optimal. + // 08:15 A --> R1 --> 08:40 F + // 08:40 F --> R4 --> 08:45 P + // 08:45 P --> R3 --> 09:00 K + List connections = RaptorRouterTestHelpers.routeEarliestArrival(rangeRaptor, STOP_A, STOP_K, + EIGHT_AM); + assertEquals(1, connections.size()); + RangeRaptorHelpers.assertConnection(connections.getFirst(), expectedDepartureTime, expectedArrivalTime, 2, + STOP_A, STOP_K); + } + static class RangeRaptorHelpers { static void assertConnection(Connection connection, LocalDateTime expectedDepartureTime, diff --git a/src/test/java/ch/naviqore/raptor/router/RaptorRouterTestBuilder.java b/src/test/java/ch/naviqore/raptor/router/RaptorRouterTestBuilder.java index 4baba259..38a461b4 100644 --- a/src/test/java/ch/naviqore/raptor/router/RaptorRouterTestBuilder.java +++ b/src/test/java/ch/naviqore/raptor/router/RaptorRouterTestBuilder.java @@ -160,6 +160,11 @@ public RaptorRouterTestBuilder withAddRoute4_RS() { return this; } + public RaptorRouterTestBuilder withAddRoute4_RS(int offset, int headway, int travelTime, int dwellTime) { + routes.add(new Route("R4", List.of("R", "P", "F", "S"), offset, headway, travelTime, dwellTime)); + return this; + } + public RaptorRouterTestBuilder withAddRoute5_AH_selfIntersecting() { routes.add(new Route("R5", List.of("A", "B", "C", "D", "E", "F", "P", "O", "N", "K", "J", "I", "B", "H"))); return this;