diff --git a/Algorithms/CSA/CSA.h b/Algorithms/CSA/CSA.h index 2ab6b1b..63b5d83 100644 --- a/Algorithms/CSA/CSA.h +++ b/Algorithms/CSA/CSA.h @@ -207,4 +207,4 @@ class CSA { Profiler profiler; }; -} +} \ No newline at end of file diff --git a/Algorithms/CSA/ULTRACSA.h b/Algorithms/CSA/ULTRACSA.h index 7024587..33fe36f 100644 --- a/Algorithms/CSA/ULTRACSA.h +++ b/Algorithms/CSA/ULTRACSA.h @@ -249,4 +249,4 @@ class ULTRACSA { Profiler profiler; }; -} +} \ No newline at end of file diff --git a/Algorithms/RAPTOR/RAPTOR.h b/Algorithms/RAPTOR/RAPTOR.h index 221a5ce..992f2f5 100644 --- a/Algorithms/RAPTOR/RAPTOR.h +++ b/Algorithms/RAPTOR/RAPTOR.h @@ -412,4 +412,416 @@ class RAPTOR { }; +template +class RAPTOR_prune { + +public: + static constexpr bool TargetPruning = TARGET_PRUNING; + using Profiler = PROFILER; + static constexpr bool Transitive = TRANSITIVE; + static constexpr bool UseMinTransferTimes = USE_MIN_TRANSFER_TIMES; + static constexpr bool PreventDirectWalking = PREVENT_DIRECT_WALKING; + static constexpr bool SeparateRouteAndTransferEntries = !Transitive | UseMinTransferTimes | PreventDirectWalking; + static constexpr int RoundFactor = SeparateRouteAndTransferEntries ? 2 : 1; + using ArrivalTime = EarliestArrivalTime; + using Type = RAPTOR; + using InitialTransferGraph = TransferGraph; + using SourceType = StopId; + + inline Journey getJourney() const noexcept { + return getEarliestJourney(targetStop); + } + +private: + struct EarliestArrivalLabel { + EarliestArrivalLabel() : arrivalTime(never), parentDepartureTime(never), parent(noStop), usesRoute(false), routeId(noRouteId) {} + int arrivalTime; + int parentDepartureTime; + StopId parent; + bool usesRoute; + union { + RouteId routeId; + Edge transferId; + }; + }; + using Round = std::vector; + +public: + RAPTOR_prune(const Data& data, const Profiler& profilerTemplate = Profiler()) : + data(data), + earliestArrival(data.numberOfStops()), + stopsUpdatedByRoute(data.numberOfStops()), + stopsUpdatedByTransfer(data.numberOfStops()), + routesServingUpdatedStops(data.numberOfRoutes()), + sourceStop(noStop), + targetStop(noStop), + sourceDepartureTime(never), + walkingDistance(INFTY), + profiler(profilerTemplate) { + if constexpr (UseMinTransferTimes) { + Assert(!data.hasImplicitBufferTimes(), "Either min transfer times have to be used OR departure buffer times have to be implicit!"); + } else { + Assert(data.hasImplicitBufferTimes(), "Either min transfer times have to be used OR departure buffer times have to be implicit!"); + } + profiler.registerExtraRounds({EXTRA_ROUND_CLEAR, EXTRA_ROUND_INITIALIZATION}); + profiler.registerPhases({PHASE_INITIALIZATION, PHASE_COLLECT, PHASE_SCAN, PHASE_TRANSFERS}); + profiler.registerMetrics({METRIC_ROUTES, METRIC_ROUTE_SEGMENTS, METRIC_EDGES, METRIC_STOPS_BY_TRIP, METRIC_STOPS_BY_TRANSFER}); + profiler.initialize(); + } + + template + RAPTOR_prune(const Data& data, const InitialTransferGraph&, const InitialTransferGraph&, const ATTRIBUTE, const Profiler& = Profiler()) : + RAPTOR_prune(data) { + } + + inline void run(const StopId source, const int departureTime, const StopId target = noStop, const size_t maxRounds = INFTY) noexcept { + profiler.start(); + profiler.startExtraRound(EXTRA_ROUND_CLEAR); + + + clear(); + profiler.doneRound(); + + profiler.startExtraRound(EXTRA_ROUND_INITIALIZATION); + profiler.startPhase(); + initialize(source, departureTime, target); + profiler.donePhase(PHASE_INITIALIZATION); + profiler.startPhase(); + relaxTransfers(); + profiler.donePhase(PHASE_TRANSFERS); + profiler.doneRound(); + + for (size_t i = 0; i < maxRounds; i++) { + profiler.startRound(); + profiler.startPhase(); + startNewRound(); + profiler.donePhase(PHASE_INITIALIZATION); + profiler.startPhase(); + collectRoutesServingUpdatedStops(); + profiler.donePhase(PHASE_COLLECT); + profiler.startPhase(); + scanRoutes(); + profiler.donePhase(PHASE_SCAN); + if (stopsUpdatedByRoute.empty()) { + profiler.doneRound(); + break; + } + if constexpr (SeparateRouteAndTransferEntries) { + profiler.startPhase(); + startNewRound(); + profiler.donePhase(PHASE_INITIALIZATION); + } + profiler.startPhase(); + relaxTransfers(); + profiler.donePhase(PHASE_TRANSFERS); + profiler.doneRound(); + } + profiler.done(); + } + + inline std::vector getJourneys() const noexcept { + return getJourneys(targetStop); + } + + inline std::vector getJourneys(const StopId stop) const noexcept { + std::vector journeys; + for (size_t i = 0; i < rounds.size(); i += RoundFactor) { + getJourney(journeys, i, stop); + } + return journeys; + } + + inline Journey getEarliestJourney(const StopId stop) const noexcept { + std::vector journeys = getJourneys(stop); + return journeys.empty() ? Journey() : journeys.back(); + } + + inline std::vector getArrivals() const noexcept { + return getArrivals(targetStop); + } + + inline std::vector getArrivals(const StopId stop) const noexcept { + Assert(data.isStop(stop), "The StopId " << stop << " does not correspond to any stop!"); + std::vector labels; + for (size_t i = 0; i < rounds.size(); i += RoundFactor) { + getArrival(labels, i, stop); + } + return labels; + } + + inline std::vector getArrivalTimes() const noexcept { + return getArrivalTimes(targetStop); + } + + inline std::vector getArrivalTimes(const StopId stop) const noexcept { + std::vector arrivalTimes; + for (size_t i = 0; i < rounds.size(); i += RoundFactor) { + getArrivalTime(arrivalTimes, i, stop); + } + return arrivalTimes; + } + + inline bool reachable(const StopId stop) const noexcept { + return earliestArrival[stop].getArrivalTime() < never; + } + + inline int getEarliestArrivalTime(const StopId stop) const noexcept { + return earliestArrival[stop].getArrivalTime(); + } + + inline int getWalkingArrivalTime() const noexcept { + return sourceDepartureTime + walkingDistance; + } + + inline int getWalkingTravelTime() const noexcept { + return walkingDistance; + } + + template + inline void clear() noexcept { + stopsUpdatedByRoute.clear(); + stopsUpdatedByTransfer.clear(); + routesServingUpdatedStops.clear(); + targetStop = noStop; + sourceDepartureTime = never; + walkingDistance = INFTY; + if constexpr (RESET_CAPACITIES) { + std::vector().swap(rounds); + std::vector(earliestArrival.size(), never).swap(earliestArrival); + } else { + rounds.clear(); + Vector::fill(earliestArrival); + } + } + + inline void reset() noexcept { + clear(); + } + + inline const Profiler& getProfiler() const noexcept { + return profiler; + } + + inline int getArrivalTime(const StopId stop, const size_t numberOfTrips) const noexcept { + size_t round = numberOfTrips * RoundFactor; + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + Assert(rounds[round][stop].arrivalTime < never, "No label found for stop " << stop << " in round " << round << "!"); + return rounds[round][stop].arrivalTime; + } + +private: + inline void initialize(const StopId source, const int departureTime, const StopId target) noexcept { + sourceStop = source; + targetStop = target; + sourceDepartureTime = departureTime; + startNewRound(); + arrivalByRoute(source, sourceDepartureTime); + currentRound()[source].parent = source; + currentRound()[source].parentDepartureTime = sourceDepartureTime; + currentRound()[source].usesRoute = false; + if constexpr (SeparateRouteAndTransferEntries) startNewRound(); + } + + inline void collectRoutesServingUpdatedStops() noexcept { + for (const StopId stop : stopsUpdatedByTransfer) { + Assert(data.isStop(stop), "Stop " << stop << " is out of range!"); + const int arrivalTime = previousRound()[stop].arrivalTime; + Assert(arrivalTime < never, "Updated stop has arrival time = never!"); + for (const RouteSegment& route : data.routesContainingStop(stop)) { + Assert(data.isRoute(route.routeId), "Route " << route.routeId << " is out of range!"); + Assert(data.stopIds[data.firstStopIdOfRoute[route.routeId] + route.stopIndex] == stop, "RAPTOR data contains invalid route segments!"); + if (route.stopIndex + 1 == data.numberOfStopsInRoute(route.routeId)) continue; + if (data.lastTripOfRoute(route.routeId)[route.stopIndex].departureTime < arrivalTime) continue; + if (routesServingUpdatedStops.contains(route.routeId)) { + routesServingUpdatedStops[route.routeId] = std::min(routesServingUpdatedStops[route.routeId], route.stopIndex); + } else { + routesServingUpdatedStops.insert(route.routeId, route.stopIndex); + } + } + } + } + + inline void scanRoutes() noexcept { + stopsUpdatedByRoute.clear(); + for (const RouteId route : routesServingUpdatedStops.getKeys()) { + profiler.countMetric(METRIC_ROUTES); + StopIndex stopIndex = routesServingUpdatedStops[route]; + const size_t tripSize = data.numberOfStopsInRoute(route); + Assert(stopIndex < tripSize - 1, "Cannot scan a route starting at/after the last stop (Route: " << route << ", StopIndex: " << stopIndex << ", TripSize: " << tripSize << ")!"); + + const StopId* stops = data.stopArrayOfRoute(route); + const StopEvent* trip = data.lastTripOfRoute(route); + StopId stop = stops[stopIndex]; + Assert(trip[stopIndex].departureTime >= previousRound()[stop].arrivalTime, "Cannot scan a route after the last trip has departed (Route: " << route << ", Stop: " << stop << ", StopIndex: " << stopIndex << ", Time: " << previousRound()[stop].arrivalTime << ", LastDeparture: " << trip[stopIndex].departureTime << ")!"); + + StopIndex parentIndex = stopIndex; + const StopEvent* firstTrip = data.firstTripOfRoute(route); + while (stopIndex < tripSize - 1) { + while ((trip > firstTrip) && ((trip - tripSize + stopIndex)->departureTime >= previousRound()[stop].arrivalTime)) { + trip -= tripSize; + parentIndex = stopIndex; + } + stopIndex++; + stop = stops[stopIndex]; + profiler.countMetric(METRIC_ROUTE_SEGMENTS); + if (arrivalByRoute(stop, trip[stopIndex].arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[stop]; + label.parent = stops[parentIndex]; + label.parentDepartureTime = trip[parentIndex].departureTime; + label.usesRoute = true; + label.routeId = route; + } + } + } + } + + template + inline void relaxTransfers() noexcept { + stopsUpdatedByTransfer.clear(); + routesServingUpdatedStops.clear(); + const int targetArrivalTime = (TargetPruning && targetStop != noStop) + ? earliestArrival[targetStop].getArrivalTime() + : never; + + for (const StopId stop : stopsUpdatedByRoute) { + const int earliestArrivalTime = SeparateRouteAndTransferEntries ? previousRound()[stop].arrivalTime : currentRound()[stop].arrivalTime; + for (const Edge edge : data.transferGraph.edgesFrom(stop)) { + if constexpr (INITIAL_TRANSFERS && PreventDirectWalking) { + if (data.transferGraph.get(ToVertex, edge) == targetStop) { + walkingDistance = data.transferGraph.get(TravelTime, edge); + continue; + } + } + profiler.countMetric(METRIC_EDGES); + const int arrivalTime = earliestArrivalTime + data.transferGraph.get(TravelTime, edge); + if (arrivalTime > targetArrivalTime) { + break; + } + Assert(data.isStop(data.transferGraph.get(ToVertex, edge)), "Graph contains edges to non stop vertices!"); + const StopId toStop = StopId(data.transferGraph.get(ToVertex, edge)); + if (arrivalByTransfer(toStop, arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[toStop]; + label.parent = stop; + label.parentDepartureTime = earliestArrivalTime; + label.usesRoute = false; + label.transferId = edge; + } + } + if constexpr (SeparateRouteAndTransferEntries) { + const int arrivalTime = earliestArrivalTime + getMinTransferTime(stop); + if (arrivalByTransfer(stop, arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[stop]; + label.parent = stop; + label.parentDepartureTime = earliestArrivalTime; + label.usesRoute = false; + } + } else { + stopsUpdatedByTransfer.insert(stop); + } + } + } + + template + inline int getMinTransferTime(const StopId stop) const noexcept { + if constexpr (IGNORE_MIN_TRANSFER_TIMES | !UseMinTransferTimes) { + suppressUnusedParameterWarning(stop); + return 0; + } else { + return data.stopData[stop].minTransferTime; + } + } + + inline Round& currentRound() noexcept { + Assert(!rounds.empty(), "Cannot return current round, because no round exists!"); + return rounds.back(); + } + + inline Round& previousRound() noexcept { + Assert(rounds.size() >= 2, "Cannot return previous round, because less than two rounds exist!"); + return rounds[rounds.size() - 2]; + } + + inline void startNewRound() noexcept { + rounds.emplace_back(data.numberOfStops()); + } + + inline bool arrivalByRoute(const StopId stop, const int time) noexcept { + Assert(data.isStop(stop), "Stop " << stop << " is out of range!"); + if constexpr (TargetPruning) if (earliestArrival[targetStop].getArrivalTimeByRoute() <= time) return false; + if (earliestArrival[stop].getArrivalTimeByRoute() <= time) return false; + profiler.countMetric(METRIC_STOPS_BY_TRIP); + currentRound()[stop].arrivalTime = time; + earliestArrival[stop].setArrivalTimeByRoute(time); + stopsUpdatedByRoute.insert(stop); + return true; + } + + inline bool arrivalByTransfer(const StopId stop, const int time) noexcept { + Assert(data.isStop(stop), "Stop " << stop << " is out of range!"); + if constexpr (TargetPruning) if (earliestArrival[targetStop].getArrivalTimeByTransfer() <= time) return false; + if (earliestArrival[stop].getArrivalTimeByTransfer() <= time) return false; + profiler.countMetric(METRIC_STOPS_BY_TRANSFER); + currentRound()[stop].arrivalTime = time; + earliestArrival[stop].setArrivalTimeByTransfer(time); + stopsUpdatedByTransfer.insert(stop); + return true; + } + + inline void getJourney(std::vector& journeys, size_t round, StopId stop) const noexcept { + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + if (rounds[round][stop].arrivalTime >= (journeys.empty() ? never : journeys.back().back().arrivalTime)) return; + Journey journey; + do { + Assert(round != size_t(-1), "Backtracking parent pointers did not pass through the source stop!"); + const EarliestArrivalLabel& label = rounds[round][stop]; + journey.emplace_back(label.parent, stop, label.parentDepartureTime, label.arrivalTime, label.usesRoute, label.routeId); + stop = label.parent; + if constexpr (SeparateRouteAndTransferEntries) { + round--; + } else { + if (label.usesRoute) round--; + } + } while (journey.back().from != sourceStop); + journeys.emplace_back(Vector::reverse(journey)); + } + + inline void getArrival(std::vector& labels, size_t round, const StopId stop) const noexcept { + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + if (rounds[round][stop].arrivalTime >= (labels.empty() ? never : labels.back().arrivalTime)) return; + labels.emplace_back(rounds[round][stop].arrivalTime, round / RoundFactor); + } + + inline void getArrivalTime(std::vector& labels, size_t round, const StopId stop) const noexcept { + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + labels.emplace_back(std::min(rounds[round][stop].arrivalTime, (labels.empty()) ? (never) : (labels.back()))); + } + +private: + const Data& data; + + std::vector rounds; + + std::vector earliestArrival; + + IndexedSet stopsUpdatedByRoute; + IndexedSet stopsUpdatedByTransfer; + IndexedMap routesServingUpdatedStops; + + StopId sourceStop; + StopId targetStop; + int sourceDepartureTime; + int walkingDistance; + + Profiler profiler; + +}; + } diff --git a/Algorithms/RAPTOR/ULTRARAPTOR.h b/Algorithms/RAPTOR/ULTRARAPTOR.h index 464dcea..1e3841c 100644 --- a/Algorithms/RAPTOR/ULTRARAPTOR.h +++ b/Algorithms/RAPTOR/ULTRARAPTOR.h @@ -477,4 +477,474 @@ class ULTRARAPTOR { }; + template +class ULTRARAPTOR_prune { + +public: + using Profiler = PROFILER; + static constexpr bool PreventDirectWalking = PREVENT_DIRECT_WALKING; + using InitialTransferType = INITIAL_TRANSFERS; + using InitialTransferGraph = typename InitialTransferType::Graph; + static constexpr bool SeparateRouteAndTransferEntries = PreventDirectWalking; + static constexpr int RoundFactor = SeparateRouteAndTransferEntries ? 2 : 1; + using ArrivalTime = EarliestArrivalTime; + using Type = ULTRARAPTOR; + using SourceType = Vertex; + +private: + struct EarliestArrivalLabel { + EarliestArrivalLabel() : arrivalTime(never), parentDepartureTime(never), parent(noVertex), usesRoute(false), routeId(noRouteId) {} + int arrivalTime; + int parentDepartureTime; + Vertex parent; + bool usesRoute; + union { + RouteId routeId; + Edge transferId; + }; + }; + using Round = std::vector; + +public: + ULTRARAPTOR_prune(const Data& data, const InitialTransferType initialTransfers, const Profiler& profilerTemplate = Profiler()) : + data(data), + initialTransfers(initialTransfers), + earliestArrival(data.numberOfStops() + 1), + stopsUpdatedByRoute(data.numberOfStops() + 1), + stopsUpdatedByTransfer(data.numberOfStops() + 1), + routesServingUpdatedStops(data.numberOfRoutes()), + sourceVertex(noVertex), + targetVertex(noVertex), + targetStop(noStop), + sourceDepartureTime(never), + profiler(profilerTemplate) { + Assert(data.hasImplicitBufferTimes(), "Departure buffer times have to be implicit!"); + profiler.registerExtraRounds({EXTRA_ROUND_CLEAR, EXTRA_ROUND_INITIALIZATION}); + profiler.registerPhases({PHASE_INITIALIZATION, PHASE_COLLECT, PHASE_SCAN, PHASE_TRANSFERS}); + profiler.registerMetrics({METRIC_ROUTES, METRIC_ROUTE_SEGMENTS, METRIC_EDGES, METRIC_STOPS_BY_TRIP, METRIC_STOPS_BY_TRANSFER}); + profiler.initialize(); + } + + template + ULTRARAPTOR_prune(const Data& data, const InitialTransferGraph& forwardGraph, const InitialTransferGraph& backwardGraph, const ATTRIBUTE weight, const Profiler& profilerTemplate = Profiler()) : + ULTRARAPTOR_prune(data, InitialTransferType(forwardGraph, backwardGraph, data.numberOfStops(), weight), profilerTemplate) { + } + + ULTRARAPTOR_prune(const Data& data, const CH::CH& chData, const Profiler& profilerTemplate = Profiler()) requires std::same_as : + ULTRARAPTOR_prune(data, chData.forward, chData.backward, Weight, profilerTemplate) { + } + + ULTRARAPTOR_prune(const Data& data, const TransferGraph& forwardGraph, const TransferGraph& backwardGraph, const Profiler& profilerTemplate = Profiler()) requires std::same_as : + ULTRARAPTOR_prune(data, forwardGraph, backwardGraph, TravelTime, profilerTemplate) { + } + + inline void run(const Vertex source, const int departureTime, const Vertex target, const size_t maxRounds = INFTY) noexcept { + profiler.start(); + profiler.startExtraRound(EXTRA_ROUND_CLEAR); + clear(); + profiler.doneRound(); + + profiler.startExtraRound(EXTRA_ROUND_INITIALIZATION); + profiler.startPhase(); + initialize(source, departureTime, target); + profiler.donePhase(PHASE_INITIALIZATION); + profiler.startPhase(); + relaxInitialTransfers(departureTime); + profiler.donePhase(PHASE_TRANSFERS); + profiler.doneRound(); + + for (size_t i = 0; i < maxRounds; i++) { + profiler.startRound(); + profiler.startPhase(); + startNewRound(); + profiler.donePhase(PHASE_INITIALIZATION); + profiler.startPhase(); + collectRoutesServingUpdatedStops(); + profiler.donePhase(PHASE_COLLECT); + profiler.startPhase(); + scanRoutes(); + profiler.donePhase(PHASE_SCAN); + if (stopsUpdatedByRoute.empty()) { + profiler.doneRound(); + break; + } + if constexpr (SeparateRouteAndTransferEntries) { + profiler.startPhase(); + startNewRound(); + profiler.donePhase(PHASE_INITIALIZATION); + } + profiler.startPhase(); + relaxIntermediateTransfers(); + profiler.donePhase(PHASE_TRANSFERS); + profiler.doneRound(); + } + profiler.done(); + } + + inline std::vector getJourneys() const noexcept { + return getJourneys(targetStop); + } + + inline std::vector getJourneys(const Vertex vertex) const noexcept { + const StopId target = (vertex == targetVertex) ? (targetStop) : (StopId(vertex)); + std::vector journeys; + for (size_t i = 0; i < rounds.size(); i += RoundFactor) { + getJourney(journeys, i, target); + } + return journeys; + } + + inline Journey getEarliestJourney(const Vertex vertex) const noexcept { + std::vector journeys = getJourneys(vertex); + return journeys.empty() ? Journey() : journeys.back(); + } + + inline std::vector getArrivals() const noexcept { + return getArrivals(targetStop); + } + + inline std::vector getArrivals(const Vertex vertex) const noexcept { + const StopId target = (vertex == targetVertex) ? (targetStop) : (StopId(vertex)); + std::vector labels; + for (size_t i = 0; i < rounds.size(); i += RoundFactor) { + getArrival(labels, i, target); + } + return labels; + } + + inline std::vector getArrivalTimes() const noexcept { + return getArrivalTimes(targetStop); + } + + inline std::vector getArrivalTimes(const Vertex vertex) const noexcept { + const StopId target = (vertex == targetVertex) ? (targetStop) : (StopId(vertex)); + std::vector arrivalTimes; + for (size_t i = 0; i < rounds.size(); i += RoundFactor) { + getArrivalTime(arrivalTimes, i, target); + } + return arrivalTimes; + } + + inline bool reachable(const Vertex vertex) const noexcept { + const StopId target = (vertex == targetVertex) ? (targetStop) : (StopId(vertex)); + return earliestArrival[target].getArrivalTime() < never; + } + + inline int getEarliestArrivalTime(const Vertex vertex) const noexcept { + const StopId target = (vertex == targetVertex) ? (targetStop) : (StopId(vertex)); + return earliestArrival[target].getArrivalTime(); + } + + inline int getEarliestArrivalTime() const noexcept { + return getEarliestArrivalTime(targetVertex); + } + + inline int getEarliestArrivalNumberOfTrips() const noexcept { + const int eat = getEarliestArrivalTime(); + for (size_t i = rounds.size() - 1; i < rounds.size(); i -= RoundFactor) { + if (rounds[i][targetStop].arrivalTime == eat) return i; + } + return -1; + } + + inline int getWalkingArrivalTime() const noexcept { + return sourceDepartureTime + initialTransfers.getDistance(); + } + + inline int getWalkingArrivalTime(const Vertex vertex) const noexcept { + return sourceDepartureTime + initialTransfers.getForwardDistance(vertex); + } + + inline int getWalkingTravelTime() const noexcept { + return initialTransfers.getDistance(); + } + + inline int getWalkingTravelTime(const Vertex vertex) const noexcept { + return initialTransfers.getDistance(vertex); + } + + inline int getDirectTransferTime() const noexcept { + return initialTransfers.getDistance(); + } + + inline Profiler& getProfiler() noexcept { + return profiler; + } + + inline int getArrivalTime(const Vertex vertex, const size_t numberOfTrips) const noexcept { + const StopId target = (vertex == targetVertex) ? (targetStop) : (StopId(vertex)); + size_t round = numberOfTrips * RoundFactor; + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][target].arrivalTime < rounds[round][target].arrivalTime)) round++; + } + Assert(rounds[round][target].arrivalTime < never, "No label found for stop " << target << " in round " << round << "!"); + return rounds[round][target].arrivalTime; + } + + template + inline void clear() noexcept { + stopsUpdatedByRoute.clear(); + stopsUpdatedByTransfer.clear(); + routesServingUpdatedStops.clear(); + targetStop = StopId(data.numberOfStops()); + sourceDepartureTime = never; + if constexpr (RESET_CAPACITIES) { + std::vector().swap(rounds); + std::vector(earliestArrival.size(), never).swap(earliestArrival); + } else { + rounds.clear(); + Vector::fill(earliestArrival); + } + } + + inline void reset() noexcept { + clear(); + } + +private: + inline void initialize(const Vertex source, const int departureTime, const Vertex target) noexcept { + sourceVertex = source; + targetVertex = target; + if (data.isStop(target)) { + targetStop = StopId(target); + } + sourceDepartureTime = departureTime; + startNewRound(); + if (data.isStop(source)) { + arrivalByRoute(StopId(source), sourceDepartureTime); + currentRound()[source].parent = source; + currentRound()[source].parentDepartureTime = sourceDepartureTime; + currentRound()[source].usesRoute = false; + if constexpr (!SeparateRouteAndTransferEntries) stopsUpdatedByTransfer.insert(StopId(source)); + } + if constexpr (SeparateRouteAndTransferEntries) startNewRound(); + } + + inline void collectRoutesServingUpdatedStops() noexcept { + for (const StopId stop : stopsUpdatedByTransfer) { + Assert(data.isStop(stop), "Stop " << stop << " is out of range!"); + const int arrivalTime = previousRound()[stop].arrivalTime; + Assert(arrivalTime < never, "Updated stop has arrival time = never!"); + for (const RouteSegment& route : data.routesContainingStop(stop)) { + Assert(data.isRoute(route.routeId), "Route " << route.routeId << " is out of range!"); + Assert(data.stopIds[data.firstStopIdOfRoute[route.routeId] + route.stopIndex] == stop, "RAPTOR data contains invalid route segments!"); + if (route.stopIndex + 1 == data.numberOfStopsInRoute(route.routeId)) continue; + if (data.lastTripOfRoute(route.routeId)[route.stopIndex].departureTime < arrivalTime) continue; + if (routesServingUpdatedStops.contains(route.routeId)) { + routesServingUpdatedStops[route.routeId] = std::min(routesServingUpdatedStops[route.routeId], route.stopIndex); + } else { + routesServingUpdatedStops.insert(route.routeId, route.stopIndex); + } + } + } + } + + inline void scanRoutes() noexcept { + stopsUpdatedByRoute.clear(); + for (const RouteId route : routesServingUpdatedStops.getKeys()) { + profiler.countMetric(METRIC_ROUTES); + StopIndex stopIndex = routesServingUpdatedStops[route]; + const size_t tripSize = data.numberOfStopsInRoute(route); + Assert(stopIndex < tripSize - 1, "Cannot scan a route starting at/after the last stop (Route: " << route << ", StopIndex: " << stopIndex << ", TripSize: " << tripSize << ")!"); + + const StopId* stops = data.stopArrayOfRoute(route); + const StopEvent* trip = data.lastTripOfRoute(route); + StopId stop = stops[stopIndex]; + Assert(trip[stopIndex].departureTime >= previousRound()[stop].arrivalTime, "Cannot scan a route after the last trip has departed (Route: " << route << ", Stop: " << stop << ", StopIndex: " << stopIndex << ", Time: " << previousRound()[stop].arrivalTime << ", LastDeparture: " << trip[stopIndex].departureTime << ")!"); + + StopIndex parentIndex = stopIndex; + const StopEvent* firstTrip = data.firstTripOfRoute(route); + while (stopIndex < tripSize - 1) { + while ((trip > firstTrip) && ((trip - tripSize + stopIndex)->departureTime >= previousRound()[stop].arrivalTime)) { + trip -= tripSize; + parentIndex = stopIndex; + } + stopIndex++; + stop = stops[stopIndex]; + profiler.countMetric(METRIC_ROUTE_SEGMENTS); + if (arrivalByRoute(stop, trip[stopIndex].arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[stop]; + label.parent = stops[parentIndex]; + label.parentDepartureTime = trip[parentIndex].departureTime; + label.usesRoute = true; + label.routeId = route; + } + } + } + } + + inline void relaxInitialTransfers(const int sourceDepartureTime) noexcept { + initialTransfers.template run(sourceVertex, targetVertex); + for (const Vertex stop : initialTransfers.getForwardPOIs()) { + if (stop == targetStop) continue; + Assert(data.isStop(stop), "Reached POI " << stop << " is not a stop!"); + Assert(initialTransfers.getForwardDistance(stop) != INFTY, "Vertex " << stop << " was not reached!"); + const int arrivalTime = sourceDepartureTime + initialTransfers.getForwardDistance(stop); + if (arrivalByTransfer(StopId(stop), arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[stop]; + label.parent = sourceVertex; + label.parentDepartureTime = sourceDepartureTime; + label.usesRoute = false; + label.transferId = noEdge; + } + } + if constexpr (!PreventDirectWalking) { + if (initialTransfers.getDistance() != INFTY) { + const int arrivalTime = sourceDepartureTime + initialTransfers.getDistance(); + if (arrivalByTransfer(targetStop, arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[targetStop]; + label.parent = sourceVertex; + label.parentDepartureTime = sourceDepartureTime; + label.usesRoute = false; + label.transferId = noEdge; + } + } + } + } + + inline void relaxIntermediateTransfers() noexcept { + stopsUpdatedByTransfer.clear(); + routesServingUpdatedStops.clear(); + const int targetArrivalTime = (targetStop != noStop) + ? earliestArrival[targetStop].getArrivalTime() + : never; + for (const StopId stop : stopsUpdatedByRoute) { + const int earliestArrivalTime = SeparateRouteAndTransferEntries ? previousRound()[stop].arrivalTime : currentRound()[stop].arrivalTime; + for (const Edge edge : data.transferGraph.edgesFrom(stop)) { + + const StopId toStop = StopId(data.transferGraph.get(ToVertex, edge)); + if (toStop == targetStop) continue; + profiler.countMetric(METRIC_EDGES); + const int arrivalTime = earliestArrivalTime + data.transferGraph.get(TravelTime, edge); + Assert(data.isStop(data.transferGraph.get(ToVertex, edge)), "Graph contains edges to non stop vertices!"); + + + if (arrivalTime > targetArrivalTime) { + break; + } + + if (arrivalByTransfer(toStop, arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[toStop]; + label.parent = stop; + label.parentDepartureTime = earliestArrivalTime; + label.usesRoute = false; + label.transferId = edge; + } + } + if (initialTransfers.getBackwardDistance(stop) != INFTY) { + const int arrivalTime = earliestArrivalTime + initialTransfers.getBackwardDistance(stop); + if (arrivalByTransfer(targetStop, arrivalTime)) { + EarliestArrivalLabel& label = currentRound()[targetStop]; + label.parent = stop; + label.parentDepartureTime = earliestArrivalTime; + label.usesRoute = false; + label.transferId = noEdge; + } + } + if constexpr (SeparateRouteAndTransferEntries) { + if (arrivalByTransfer(stop, earliestArrivalTime)) { + EarliestArrivalLabel& label = currentRound()[stop]; + label.parent = stop; + label.parentDepartureTime = earliestArrivalTime; + label.usesRoute = false; + } + } else { + stopsUpdatedByTransfer.insert(stop); + } + } + } + + inline Round& currentRound() noexcept { + Assert(!rounds.empty(), "Cannot return current round, because no round exists!"); + return rounds.back(); + } + + inline Round& previousRound() noexcept { + Assert(rounds.size() >= 2, "Cannot return previous round, because less than two rounds exist!"); + return rounds[rounds.size() - 2]; + } + + inline void startNewRound() noexcept { + rounds.emplace_back(data.numberOfStops() + 1); + } + + inline bool arrivalByRoute(const StopId stop, const int time) noexcept { + Assert(data.isStop(stop), "Stop " << stop << " is out of range!"); + if (earliestArrival[targetStop].getArrivalTimeByRoute() <= time) return false; + if (earliestArrival[stop].getArrivalTimeByRoute() <= time) return false; + profiler.countMetric(METRIC_STOPS_BY_TRIP); + currentRound()[stop].arrivalTime = time; + earliestArrival[stop].setArrivalTimeByRoute(time); + stopsUpdatedByRoute.insert(stop); + return true; + } + + inline bool arrivalByTransfer(const StopId stop, const int time) noexcept { + Assert(data.isStop(stop) || stop == targetStop, "Stop " << stop << " is out of range!"); + if (earliestArrival[targetStop].getArrivalTimeByTransfer() <= time) return false; + if (earliestArrival[stop].getArrivalTimeByTransfer() <= time) return false; + profiler.countMetric(METRIC_STOPS_BY_TRANSFER); + currentRound()[stop].arrivalTime = time; + earliestArrival[stop].setArrivalTimeByTransfer(time); + if (data.isStop(stop)) stopsUpdatedByTransfer.insert(stop); + return true; + } + + inline void getJourney(std::vector& journeys, size_t round, StopId stop) const noexcept { + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + if (rounds[round][stop].arrivalTime >= (journeys.empty() ? never : journeys.back().back().arrivalTime)) return; + Journey journey; + do { + Assert(round != size_t(-1), "Backtracking parent pointers did not pass through the source stop!"); + const EarliestArrivalLabel& label = rounds[round][stop]; + journey.emplace_back(label.parent, stop, label.parentDepartureTime, label.arrivalTime, label.usesRoute, label.routeId); + Assert(data.isStop(label.parent) || label.parent == sourceVertex, "Backtracking parent pointers reached a vertex (" << label.parent << ")!"); + stop = StopId(label.parent); + if constexpr (SeparateRouteAndTransferEntries) { + round--; + } else { + if (label.usesRoute) round--; + } + } while (journey.back().from != sourceVertex); + journeys.emplace_back(Vector::reverse(journey)); + } + + inline void getArrival(std::vector& labels, size_t round, const StopId stop) const noexcept { + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + if (rounds[round][stop].arrivalTime >= (labels.empty() ? never : labels.back().arrivalTime)) return; + labels.emplace_back(rounds[round][stop].arrivalTime, round / RoundFactor); + } + + inline void getArrivalTime(std::vector& labels, size_t round, const StopId stop) const noexcept { + if constexpr (SeparateRouteAndTransferEntries) { + if ((round + 1 < rounds.size()) && (rounds[round + 1][stop].arrivalTime < rounds[round][stop].arrivalTime)) round++; + } + labels.emplace_back(std::min(rounds[round][stop].arrivalTime, (labels.empty()) ? (never) : (labels.back()))); + } + +private: + const Data& data; + + InitialTransferType initialTransfers; + + std::vector rounds; + + std::vector earliestArrival; + + IndexedSet stopsUpdatedByRoute; + IndexedSet stopsUpdatedByTransfer; + IndexedMap routesServingUpdatedStops; + + Vertex sourceVertex; + Vertex targetVertex; + StopId targetStop; + int sourceDepartureTime; + + Profiler profiler; + +}; } diff --git a/DataStructures/RAPTOR/Data.h b/DataStructures/RAPTOR/Data.h index bc18750..37ea6e1 100644 --- a/DataStructures/RAPTOR/Data.h +++ b/DataStructures/RAPTOR/Data.h @@ -610,6 +610,13 @@ class Data { } } + // --- + inline void sortTransferGraphEdgesByTravelTime() noexcept { + transferGraph.sortEdges(TravelTime); + } + + // --- + inline void applyVertexPermutation(const Permutation& permutation, const bool permutateStops = true) noexcept { Permutation splitPermutation = permutation.splitAt(numberOfStops()); if (!permutateStops) { @@ -773,20 +780,23 @@ class Data { std::ofstream file(fileName); Assert(file, "cannot open file: " << fileName); Assert(file.is_open(), "cannot open file: " << fileName); - file << "LineId,TripId,StopIndex,ArrivalTime,DepartureTime\n"; + file << "LineId,TripId,StopIndex,StopId,ArrivalTime,DepartureTime\n"; for (const RouteId route : routes()) { + const StopId* stops = stopArrayOfRoute(route); // Get the array of StopIds for the current route const StopEvent* stopEvents = firstTripOfRoute(route); const size_t tripLength = numberOfStopsInRoute(route); for (size_t i = 0; i < numberOfTripsInRoute(route); i++) { for (size_t j = 0; j < tripLength; j++) { const StopEvent& stopEvent = stopEvents[(i * tripLength) + j]; - file << route.value() << "," << i << "," << j << "," << stopEvent.arrivalTime << "," << stopEvent.departureTime << "\n"; + const StopId stopId = stops[j]; // Get the StopId corresponding to the StopIndex + file << route.value() << "," << i << "," << j << "," << stopId.value() << "," << stopEvent.arrivalTime << "," << stopEvent.departureTime << "\n"; } } } file.close(); } + inline void writeFootpathCSV(const std::string& fileName) const noexcept { std::ofstream file(fileName); Assert(file, "cannot open file: " << fileName); diff --git a/Runnables/Commands/BenchmarkULTRA.h b/Runnables/Commands/BenchmarkULTRA.h index 5ccc1dc..0d8e9a1 100644 --- a/Runnables/Commands/BenchmarkULTRA.h +++ b/Runnables/Commands/BenchmarkULTRA.h @@ -18,6 +18,8 @@ using namespace Shell; #include "../../Algorithms/RAPTOR/ULTRARAPTOR.h" #include "../../Algorithms/TripBased/Query/Query.h" #include "../../Algorithms/TripBased/Query/TransitiveQuery.h" +#include "../../DataStructures/RAPTOR/Entities/Journey.h" +#include "../../DataStructures/CSA/Entities/Journey.h" #include "../../DataStructures/Queries/Queries.h" #include "../../DataStructures/CSA/Data.h" @@ -107,7 +109,6 @@ class RunHLCSAQueries : public ParameterizedCommand { algorithm.getProfiler().printStatistics(); } }; - class RunULTRACSAQueries : public ParameterizedCommand { public: @@ -142,25 +143,165 @@ class RunTransitiveRAPTORQueries : public ParameterizedCommand { ParameterizedCommand(shell, "runTransitiveRAPTORQueries", "Runs the given number of random transitive RAPTOR queries.") { addParameter("RAPTOR input file"); addParameter("Number of queries"); + addParameter("Pruning rule (0 or 1)"); } virtual void execute() noexcept { RAPTOR::Data raptorData = RAPTOR::Data::FromBinary(getParameter("RAPTOR input file")); raptorData.useImplicitDepartureBufferTimes(); + raptorData.writeCSV(""); raptorData.printInfo(); - RAPTOR::RAPTOR algorithm(raptorData); const size_t n = getParameter("Number of queries"); const std::vector queries = generateRandomStopQueries(raptorData.numberOfStops(), n); - double numJourneys = 0; - for (const StopQuery& query : queries) { - algorithm.run(query.source, query.departureTime, query.target); - numJourneys += algorithm.getJourneys().size(); + // READ THE NEW INTEGER PARAMETER + const int pruningRule = getParameter("Pruning rule (0 or 1)"); + + // We use an if-else block to instantiate the correct version of the algorithm, + // as the `ENABLE_PRUNING` template parameter must be a compile-time constant. + if (pruningRule == 1) { + // Instantiate with TARGET_PRUNING=true and ENABLE_PRUNING=1 + RAPTOR::RAPTOR algorithm(raptorData); + + double numJourneys = 0; + for (const StopQuery& query : queries) { + algorithm.run(query.source, query.departureTime, query.target); + numJourneys += algorithm.getJourneys().size(); + } + algorithm.getProfiler().printStatistics(); + std::cout << "Avg. journeys: " << String::prettyDouble(numJourneys / n) << std::endl; + } else { + // Instantiate with TARGET_PRUNING=true and ENABLE_PRUNING=0 (default) + RAPTOR::RAPTOR_prune algorithm(raptorData); + + double numJourneys = 0; + for (const StopQuery& query : queries) { + algorithm.run(query.source, query.departureTime, query.target); + numJourneys += algorithm.getJourneys().size(); + } + algorithm.getProfiler().printStatistics(); + std::cout << "Avg. journeys: " << String::prettyDouble(numJourneys / n) << std::endl; } - algorithm.getProfiler().printStatistics(); - std::cout << "Avg. journeys: " << String::prettyDouble(numJourneys/n) << std::endl; + } +}; + +class TestTransitiveRAPTORQueries : public ParameterizedCommand { + +public: + TestTransitiveRAPTORQueries(BasicShell& shell) : + ParameterizedCommand(shell, "testTransitiveRAPTORQueries", "Tests a specific transitive RAPTOR query.") { + addParameter("RAPTOR input file"); + addParameter("sourceStop"); + addParameter("targetStop"); + addParameter("startTime"); + } + + virtual void execute() noexcept { + RAPTOR::Data raptorData = RAPTOR::Data::FromBinary(getParameter("RAPTOR input file")); + raptorData.useImplicitDepartureBufferTimes(); + raptorData.printInfo(); + + const StopId sourceStop = StopId(getParameter("sourceStop")); + const StopId targetStop = StopId(getParameter("targetStop")); + + const int startTime = getParameter("startTime"); + + std::cout << "Running query from stop " << sourceStop << " to stop " << targetStop << " at time " << startTime << std::endl; + + RAPTOR::RAPTOR algorithm(raptorData); + algorithm.run(sourceStop, startTime, targetStop); + + // Corrected line: calling the existing getEarliestJourney function + const RAPTOR::Journey journey = algorithm.getEarliestJourney(targetStop); + std::cout << "Journey: " << journey << std::endl; + + } +}; + +class TestTransitiveCSAQueries : public ParameterizedCommand { + +public: + TestTransitiveCSAQueries(BasicShell& shell) : + ParameterizedCommand(shell, "testTransitiveCSAQueries", "Tests a specific transitive CSA query.") { + addParameter("CSA input file"); + addParameter("sourceStop"); + addParameter("targetStop"); + addParameter("startTime"); + } + + virtual void execute() noexcept { + CSA::Data csaData = CSA::Data::FromBinary(getParameter("CSA input file")); + csaData.sortConnectionsAscending(); + csaData.printInfo(); + + const StopId sourceStop = StopId(getParameter("sourceStop")); + const StopId targetStop = StopId(getParameter("targetStop")); + const int startTime = getParameter("startTime"); + + std::cout << "Running query from stop " << sourceStop << " to stop " << targetStop << " at time " << startTime << std::endl; + + CSA::CSA algorithm(csaData); + algorithm.run(sourceStop, startTime, targetStop); + + const int arrivalTime = algorithm.getEarliestArrivalTime(targetStop); + std::cout << "Earliest Arrival Time: " << arrivalTime << std::endl; + + const CSA::Journey journey = algorithm.getJourney(targetStop); + std::cout << "Journey: " << journey << std::endl; + } +}; + +class CheckRAPTORPruning : public ParameterizedCommand { + +public: + CheckRAPTORPruning(BasicShell& shell) : + ParameterizedCommand(shell, "checkRAPTORPruning", "Checks if RAPTOR pruning rules yield the same results as no pruning.") { + addParameter("RAPTOR input file"); + addParameter("Number of queries"); + } + + virtual void execute() noexcept { + RAPTOR::Data raptorData = RAPTOR::Data::FromBinary(getParameter("RAPTOR input file")); + raptorData.useImplicitDepartureBufferTimes(); + + const size_t n = getParameter("Number of queries"); + // Generate StopQueries, not VertexQueries + const std::vector queries = generateRandomStopQueries(raptorData.numberOfStops(), n); + std::vector results_no_pruning; + std::vector results_pruning_1; + + // Run with pruning rule 0 (no pruning) + std::cout << "--- Running with No Pruning (Rule 0) ---" << std::endl; + RAPTOR::RAPTOR algo_no_pruning(raptorData); + for (const StopQuery& query : queries) { + algo_no_pruning.run(query.source, query.departureTime, query.target); + results_no_pruning.push_back(algo_no_pruning.getEarliestArrivalTime(query.target)); + } + std::cout << "--- Statistics for No Pruning (Rule 0) ---" << std::endl; + algo_no_pruning.getProfiler().printStatistics(); + + // Run with pruning rule 1 + std::cout << "\n--- Running with Pruning Rule 1 ---" << std::endl; + // The transfer graph must be sorted for pruning rule 1 to be effective + raptorData.sortTransferGraphEdgesByTravelTime(); + RAPTOR::RAPTOR_prune algo_pruning_1(raptorData); + for (const StopQuery& query : queries) { + algo_pruning_1.run(query.source, query.departureTime, query.target); + results_pruning_1.push_back(algo_pruning_1.getEarliestArrivalTime(query.target)); + } + std::cout << "--- Statistics for Pruning Rule 1 ---" << std::endl; + algo_pruning_1.getProfiler().printStatistics(); + + // Compare the results + bool pruning_1_correct = (results_no_pruning == results_pruning_1); + std::cout << "\n--- Comparison Results ---" << std::endl; + if (pruning_1_correct) { + std::cout << "Pruning rule 1 results match no-pruning results. The pruning is correct." << std::endl; + } else { + std::cout << "ERROR: Pruning rule 1 failed comparison. Results are not identical." << std::endl; + } } }; @@ -234,18 +375,124 @@ class RunULTRARAPTORQueries : public ParameterizedCommand { addParameter("RAPTOR input file"); addParameter("CH data"); addParameter("Number of queries"); + addParameter("Pruning rule (0 or 1)"); } virtual void execute() noexcept { RAPTOR::Data raptorData = RAPTOR::Data::FromBinary(getParameter("RAPTOR input file")); raptorData.useImplicitDepartureBufferTimes(); + raptorData.sortTransferGraphEdgesByTravelTime(); // Call to sort the transfer graph edges raptorData.printInfo(); CH::CH ch(getParameter("CH data")); - RAPTOR::ULTRARAPTOR algorithm(raptorData, ch); + // RAPTOR::ULTRARAPTOR algorithm(raptorData, ch); + const size_t n = getParameter("Number of queries"); + // Read the pruning rule from the user + const int pruningRule = getParameter("Pruning rule (0 or 1)"); + const std::vector queries = generateRandomVertexQueries(ch.numVertices(), n); + // double numJourneys = 0; + //for (const VertexQuery& query : queries) { + // algorithm.run(query.source, query.departureTime, query.target); + // numJourneys += algorithm.getJourneys().size(); + //} + //algorithm.getProfiler().printStatistics(); + auto runAndProfile = [&](auto& algorithm) { + double numJourneys = 0; + for (const VertexQuery& query : queries) { + algorithm.run(query.source, query.departureTime, query.target); + numJourneys += algorithm.getJourneys().size(); + } + algorithm.getProfiler().printStatistics(); + std::cout << "Avg. journeys: " << String::prettyDouble(numJourneys/n) << std::endl; + }; + + switch (pruningRule) { + case 0: { + RAPTOR::ULTRARAPTOR algorithm(raptorData, ch); + runAndProfile(algorithm); + break; + } + case 1: { + RAPTOR::ULTRARAPTOR_prune algorithm(raptorData, ch); + runAndProfile(algorithm); + break; + } + default: { + std::cout << "Invalid pruning rule. Please choose 0 or 1" << std::endl; + break; + } + } + } +}; + +class CheckULTRARAPTORPruning : public ParameterizedCommand { + +public: + CheckULTRARAPTORPruning(BasicShell& shell) : + ParameterizedCommand(shell, "checkULTRARAPTORPruning", "Checks if pruning rules yield the same results as no pruning.") { + addParameter("RAPTOR input file"); + addParameter("CH data"); + addParameter("Number of queries"); + } + + virtual void execute() noexcept { + RAPTOR::Data raptorData = RAPTOR::Data::FromBinary(getParameter("RAPTOR input file")); + raptorData.useImplicitDepartureBufferTimes(); + CH::CH ch(getParameter("CH data")); const size_t n = getParameter("Number of queries"); const std::vector queries = generateRandomVertexQueries(ch.numVertices(), n); + std::vector results_no_pruning; + std::vector results_pruning_1; + std::vector results_pruning_2; + + // Run with pruning rule 0 (no pruning) + RAPTOR::ULTRARAPTOR algo_no_pruning(raptorData, ch); + for (const VertexQuery& query : queries) { + algo_no_pruning.run(query.source, query.departureTime, query.target); + results_no_pruning.push_back(algo_no_pruning.getEarliestArrivalTime()); + } + std::cout << "--- Statistics for No Pruning (Rule 0) ---" << std::endl; + algo_no_pruning.getProfiler().printStatistics(); + + + // Run with pruning rule 1 + raptorData.sortTransferGraphEdgesByTravelTime(); + RAPTOR::ULTRARAPTOR_prune algo_pruning_1(raptorData, ch); + for (const VertexQuery& query : queries) { + algo_pruning_1.run(query.source, query.departureTime, query.target); + results_pruning_1.push_back(algo_pruning_1.getEarliestArrivalTime()); + } + std::cout << "--- Statistics for Pruning Rule 1 ---" << std::endl; + algo_pruning_1.getProfiler().printStatistics(); + + // Compare the results + bool pruning_1_correct = (results_no_pruning == results_pruning_1); + + if (!pruning_1_correct) { + std::cout << "Pruning rule 1 failed comparison." << std::endl; + } + } +}; + +class RunULTRARAPTORQueries_updated : public ParameterizedCommand { + +public: + RunULTRARAPTORQueries_updated(BasicShell& shell) : + ParameterizedCommand(shell, "runULTRARAPTORQueries", "Runs the given number of random ULTRA-RAPTOR queries.") { + addParameter("RAPTOR input file"); + addParameter("CH data"); + addParameter("Number of queries"); + } + + virtual void execute() noexcept { + RAPTOR::Data raptorData = RAPTOR::Data::FromBinary(getParameter("RAPTOR input file")); + raptorData.useImplicitDepartureBufferTimes(); + raptorData.printInfo(); + CH::CH ch(getParameter("CH data")); + RAPTOR::ULTRARAPTOR algorithm(raptorData, ch); + const size_t n = getParameter("Number of queries"); + const std::vector queries = generateRandomVertexQueries(ch.numVertices(), n); double numJourneys = 0; for (const VertexQuery& query : queries) { algorithm.run(query.source, query.departureTime, query.target); @@ -284,7 +531,6 @@ class RunTransitiveTBQueries : public ParameterizedCommand { }; class RunULTRATBQueries : public ParameterizedCommand { - public: RunULTRATBQueries(BasicShell& shell) : ParameterizedCommand(shell, "runULTRATBQueries", "Runs the given number of random ULTRA-TB queries.") { diff --git a/Runnables/ULTRA.cpp b/Runnables/ULTRA.cpp index 358a433..777a66d 100644 --- a/Runnables/ULTRA.cpp +++ b/Runnables/ULTRA.cpp @@ -42,6 +42,10 @@ int main(int argc, char** argv) { new RunDijkstraRAPTORQueries(shell); new RunHLRAPTORQueries(shell); new RunULTRARAPTORQueries(shell); + new CheckULTRARAPTORPruning(shell); + new CheckRAPTORPruning(shell); + new TestTransitiveRAPTORQueries(shell); + new TestTransitiveCSAQueries(shell); new RunTransitiveTBQueries(shell); new RunULTRATBQueries(shell);