Postdata
WorkResearchAbout
WorkResearchAbout
Postdata
WorkResearchAboutContact

© 2026 Postdata. All rights reserved.

  1. Research
  2. /Real-Time Public Transit Routing with Unlimited Transfers

Real-Time Public Transit Routing with Unlimited Transfers

public transitroutingalgorithmsliterature review

Your phone answers "fastest way across town" in milliseconds — but car routing and transit routing are secretly very different problems. A tour from plain Dijkstra to the ULTRA family, and why timetables make everything harder.

Ask your phone for the fastest way across the city and you get an answer in milliseconds. Behind that tap sits decades of algorithm engineering — and, it turns out, two very different worlds. Routing a car on a road network and routing a passenger through buses and trains look like the same problem, but the tricks that make car routing answer in microseconds quietly fall apart on a timetable.

This post is a tour of the main algorithms in both worlds — from plain old Dijkstra to the state-of-the-art ULTRA family — and why transit is the harder cousin. We'll start with road routing (Dijkstra, A*, Contraction Hierarchies, Bidirectional Dijkstra, Hub Labelling), move on to the core transit algorithms (RAPTOR, CSA, Trip-Based, Transfer Patterns), and finish with what happens once you let people walk as far as they like between stops: multimodal, unlimited-transfer routing.

A quick map of where we're going: road networks have two gifts that make them fast — edge weights that don't change with time, and a natural hierarchy (you leave a side street, hit an arterial, take the motorway, and reverse the pattern at the other end). Transit has neither. That single fact is why most of this post exists.

Road Network Routing

Dijkstra's Algorithm

Dijkstra's algorithm is a one-to-one and one-to-many shortest-path algorithm, which computes shortest paths from a single source in any graph with non-negative edge weights. Each vertex maintains a tentative distance dist(v)\text{dist}(v)dist(v), initialised to ∞\infty∞ except the source at 000. The algorithm repeatedly settles the unsettled vertex with the smallest tentative distance and relaxes its outgoing edges, updating neighbours if a shorter path is found. Once settled, a vertex is not revisited. There are two flavours: the one-to-many variant runs to completion, settling every reachable vertex, while the one-to-one variant — the one you want for a single trip — stops the moment the target is settled, because its distance is already optimal at that point.

The asymptotic complexity in the classical version of Dijkstra is O((∣E∣+∣V∣)log⁡∣V∣)\mathcal{O}((|E| + |V|) \log |V|)O((∣E∣+∣V∣)log∣V∣). This follows from two operations. Extract-min runs ∣V∣|V|∣V∣ times and decrease-key runs up to ∣E∣|E|∣E∣ times, both at O(log⁡∣V∣)\mathcal{O}(\log |V|)O(log∣V∣) cost per call in a binary heap. However, if we replace the standard heap with a Fibonacci one, the cost of the decrease-key operation will be reduced from O(log⁡∣V∣)\mathcal{O}(\log |V|)O(log∣V∣) to O(1)\mathcal{O}(1)O(1). It will lead to a decrease in the asymptotic complexity of Dijkstra search to O(∣E∣+∣V∣log⁡∣V∣)\mathcal{O}(|E| + |V| \log |V|)O(∣E∣+∣V∣log∣V∣). However, in practice, Fibonacci heaps win asymptotically only on dense graphs, and they pay for it with large constants and four pointers per node. Engineered routing libraries such as RoutingKit and OSRM avoid them and use a standard heap instead, which is faster on sparse road networks despite the worst-case bound.

In memory, Dijkstra is cheap. It stores a tentative distance from the source to each vertex, a priority queue with at most ∣V∣|V|∣V∣ entries, and a parent pointer per vertex in case we need to reconstruct the path. These are all linear in the number of vertices, so together with the graph itself, stored as an adjacency list, the total is O(∣V∣+∣E∣)\mathcal{O}(|V| + |E|)O(∣V∣+∣E∣), which dominates when there are more edges than vertices.

Dijkstra's algorithm on a six-vertex transit graph departing from A at 8:00, in six steps. Edge weights are travel times in minutes. Blue = vertex being settled; red arrows = edges being relaxed; green/asterisk = vertex settled with final arrival time. The shortest path is A → D → B → C, arriving 8:30.
Dijkstra's algorithm on a six-vertex transit graph departing from A at 8:00, in six steps. Edge weights are travel times in minutes. Blue = vertex being settled; red arrows = edges being relaxed; green/asterisk = vertex settled with final arrival time. The shortest path is A → D → B → C, arriving 8:30.

A*

Dijkstra has one weakness. Its search is not goal-directed. It spreads out in every direction and ignores where the target is.

A* fixes this. It adds a heuristic h(v)h(v)h(v) that estimates the remaining distance from a vertex vvv to the target ttt. The priority queue is then ordered by f(v)=g(v)+h(v)f(v) = g(v) + h(v)f(v)=g(v)+h(v), where g(v)g(v)g(v) is the distance from the source. The heuristic pulls the search towards the target.

The heuristic has to be chosen carefully. To keep the result optimal, hhh must be admissible: it never overestimates the real distance to ttt. The graph-search version, which never reopens a settled vertex, also needs hhh to be consistent: h(u)≤τtra(u,v)+h(v)h(u) \leq \tau_{\text{tra}}(u,v) + h(v)h(u)≤τtra​(u,v)+h(v) for every edge (u,v)(u,v)(u,v). On road networks the straight-line Euclidean distance works well. If the edge weights are travel times, we divide it by the maximum speed so it stays admissible.

A* is tied to one target. So it answers one-to-one queries only. In a one-to-many setup there is no fixed target, so it gives no benefit. By default it needs no preprocessing. Some heuristics are the exception, such as the landmark-based ALT.

A* on the same graph and query A → C, with a consistent heuristic $h$ giving a lower bound on the remaining time to C. The queue is ordered by $f = \tau + h$. A* settles only A, D, B, C and stops the moment C is popped; off-route vertices E ($f=8{:}32$) and F ($f=8{:}38$) are reached but never settled. Four vertices settled here against six for plain Dijkstra.
A* on the same graph and query A → C, with a consistent heuristic $h$ giving a lower bound on the remaining time to C. The queue is ordered by $f = \tau + h$. A* settles only A, D, B, C and stops the moment C is popped; off-route vertices E ($f=8{:}32$) and F ($f=8{:}38$) are reached but never settled. Four vertices settled here against six for plain Dijkstra.

A* reuses the same graph data structure as Dijkstra. It also has the same worst-case asymptotic complexity as Dijkstra. The win is practical, not asymptotic. A good heuristic settles far fewer vertices, so on road networks, A* is usually much faster in practice.

Contraction Hierarchies (CH)

The Contraction Hierarchies algorithm is a precomputation technique motivated by an observation about how roads were built. A journey from one suburb to another typically follows a fixed pattern: leave on a local street, join a larger arterial, merge onto a motorway, exit onto a regional road, and arrive back on local streets. Road networks exhibit a natural hierarchy of importance, and long shortest paths consistently follow this structure.

Sanders and Schultes formalised this as Highway Hierarchies, showing that restricting the search to progressively more important roads yields substantial speedups.

OpenStreetMap rendering of Soho, London, illustrating the road hierarchy. Thick orange roads are primary roads; yellow lines are secondary roads; thin white lines are residential streets.

Contraction Hierarchies extend this idea further and automatically calculate the hierarchy from edge weights, without requiring road category labels. Preprocessing assigns each vertex a rank and contracts the vertices one by one in ascending rank order. Contracting a vertex vvv means that we remove it from the graph and add shortcut edges between its higher-ranked neighbours to preserve all shortest-path distances. A shortcut (u,w)(u, w)(u,w) is added only when no path of equal or lesser cost exists through already-contracted vertices (witness path). The procedure that looks for such a path is called the witness search.

The primary metric for calculating a vertex rank is the edge difference. It is equal to shortcuts added minus edges removed when contracting a vertex. Contracting low-degree vertices first keeps the graph sparse and maintains the total number of shortcuts comparable to the number of original edges.

Full contraction of the six-vertex graph in rank order D, F, E, A, C, B. Red border = vertex being contracted; × = contracted; red = edges removed; blue dashed = shortcuts. Step 2 adds A–B (18) and B–E (15); Step 3 adds E–C (23); Step 4 adds none. The augmented graph carries the eight original edges plus three shortcuts.
Full contraction of the six-vertex graph in rank order D, F, E, A, C, B. Red border = vertex being contracted; × = contracted; red = edges removed; blue dashed = shortcuts. Step 2 adds A–B (18) and B–E (15); Step 3 adds E–C (23); Step 4 adds none. The augmented graph carries the eight original edges plus three shortcuts.

The asymptotic complexity of CH preprocessing is O(∣E∣⋅∣V∣)\mathcal{O}(|E| \cdot |V|)O(∣E∣⋅∣V∣) in the worst-case scenario, since running the contraction for each node, while running the witness search for all of them, might involve search over all edges.

In terms of memory, the CH graph can be estimated as O(∣V∣+∣E′∣)\mathcal{O}(|V| + |E'|)O(∣V∣+∣E′∣), where E′E'E′ is the original edges together with the shortcuts. In practice, ∣E′∣|E'|∣E′∣ can even be smaller than ∣E∣|E|∣E∣. The witness search significantly reduces the number of added shortcuts. Also, a CH stores each bidirectional edge only once, with forward and backward flags. So on road networks, the CH graph often ends up with fewer edges than the input graph. However, on graphs that do not have a road structure, the contraction can add many more shortcuts, up to O(∣V∣2)\mathcal{O}(|V|^2)O(∣V∣2), and then the CH graph takes more space than the input.

Bidirectional Dijkstra (Bi-Dijkstra)

Bidirectional Dijkstra is a one-to-one shortest path algorithm, which runs two simultaneous searches: forward from the source sss and backward from the target ttt. The algorithm terminates when the minimum key across both queues exceeds μ=min⁡v{distf(v)+distb(v)}\mu = \min_v \{ \text{dist}_f(v) + \text{dist}_b(v) \}μ=minv​{distf​(v)+distb​(v)}. In a CH graph, the forward search follows only upward edges from sss, and the backward search follows only upward edges from ttt. The two frontiers meet at the apex without visiting contracted vertices.

The asymptotic complexity of Bi-Dijkstra over a CH graph is O((∣E′∣+∣V∣)log⁡∣V∣)\mathcal{O}((|E'| + |V|) \log |V|)O((∣E′∣+∣V∣)log∣V∣), or O(∣E′∣+∣V∣⋅log⁡∣V∣)\mathcal{O}(|E'| + |V|\cdot \log |V|)O(∣E′∣+∣V∣⋅log∣V∣) with a Fibonacci heap, where E′E'E′ includes original edges and inserted shortcuts. Although ∣E′∣>∣E∣|E'| > |E|∣E′∣>∣E∣, the CH query runs much faster than plain Dijkstra in practice. Both searches follow only upward edges and are independent, making them easy to parallelise. Also, the inserted shortcuts let the search move much faster through the graph. On continental road networks, the CH query settles a few hundred to a few thousand vertices, whereas plain Dijkstra settles millions.

Bidirectional Dijkstra on the augmented CH graph, query A → C. Each search follows only edges to a higher-ranked vertex. (a) Forward from A reaches B at 8:18 via the shortcut A → B. (b) Backward from C gives $b(B)=12$. (c) The frontiers meet at the apex B with $8{:}18+12 = 8{:}30$; the shortcut A → B unpacks to A → D → B.
Bidirectional Dijkstra on the augmented CH graph, query A → C. Each search follows only edges to a higher-ranked vertex. (a) Forward from A reaches B at 8:18 via the shortcut A → B. (b) Backward from C gives $b(B)=12$. (c) The frontiers meet at the apex B with $8{:}18+12 = 8{:}30$; the shortcut A → B unpacks to A → D → B.

Industry deployment. CH is the most deployed algorithm for road routing in production systems. Open-source engines OSRM and GraphHopper both use CH as their primary preprocessing technique. It achieves sub-millisecond queries on continental OpenStreetMap data.

Bucket-CH

Bucket-CH is a modification of CH for one-to-many queries. The algorithm operates in three phases.

The first phase runs standard CH precomputation on G=(V,E)G = (V, E)G=(V,E). It produces the upward graph G↑G^{\uparrow}G↑ and the downward graph G↓G^{\downarrow}G↓.

The second phase operates on the fixed set of targets Vt⊆VV_t \subseteq VVt​⊆V. For each target t∈Vtt \in V_tt∈Vt​, a backward search is run on G↓G^{\downarrow}G↓. Each vertex vvv found by this search stores a tuple (t,dist(v,t))(t, \mathrm{dist}(v, t))(t,dist(v,t)) in its bucket, where dist(v,t)\mathrm{dist}(v, t)dist(v,t) is a distance between vvv and ttt. This phase is offline and performed once per target set.

The third phase answers a query from a source sss. A forward search is run on G↑G^{\uparrow}G↑. For each vertex vvv settled by this search, its bucket is evaluated. Each entry (t,dist(v,t))(t, \mathrm{dist}(v, t))(t,dist(v,t)) yields a candidate distance dist(s,v)+dist(v,t)\mathrm{dist}(s, v) + \mathrm{dist}(v, t)dist(s,v)+dist(v,t), which updates the tentative distance to ttt if it improves on the best value seen so far. After the forward search finishes, the algorithm computes the shortest-path distance from sss to every t∈Vtt \in V_tt∈Vt​ in a single pass.

Bucket-CH for one-to-many queries. Step 1 (preprocessing): a backward Dijkstra from each stop fills buckets on road nodes. Step 2 (query): one forward Dijkstra from $s$ reads the buckets to recover stop distances, e.g. $\mathrm{dist}(s,p_1)=8$, $\mathrm{dist}(s,p_2)=5$.
Bucket-CH for one-to-many queries. Step 1 (preprocessing): a backward Dijkstra from each stop fills buckets on road nodes. Step 2 (query): one forward Dijkstra from $s$ reads the buckets to recover stop distances, e.g. $\mathrm{dist}(s,p_1)=8$, $\mathrm{dist}(s,p_2)=5$.

Preprocessing in Bucket-CH has two parts. The first is a CH build with asymptotic complexity O(∣V∣⋅∣E∣)\mathcal{O}(|V| \cdot |E|)O(∣V∣⋅∣E∣). The second is bucket construction over the target set VtV_tVt​, costing O(∣Vt∣(∣E′∣+∣V∣)log⁡∣V∣)\mathcal{O}(|V_t|(|E'| + |V|) \log |V|)O(∣Vt​∣(∣E′∣+∣V∣)log∣V∣). Both parts are performed offline. The query then runs a single forward Dijkstra from sss followed by bucket scans at each settled vertex, with worst-case complexity O ⁣((∣E′∣+∣V∣)log⁡∣V∣+∑v∈F(s)∣B(v)∣)\mathcal{O}\!\left((|E'| + |V|) \log |V| + \sum_{v \in \mathcal{F}(s)} |\mathcal{B}(v)|\right)O((∣E′∣+∣V∣)log∣V∣+∑v∈F(s)​∣B(v)∣) without a Fibonacci heap, where F(s)\mathcal{F}(s)F(s) is the forward search space and ∣B(v)∣|\mathcal{B}(v)|∣B(v)∣ is the bucket size at vertex vvv.

Running ∣Vt∣|V_t|∣Vt​∣ independent CH queries would cost O(∣Vt∣(∣E′∣+∣V∣)log⁡∣V∣)\mathcal{O}(|V_t|(|E'| + |V|) \log |V|)O(∣Vt​∣(∣E′∣+∣V∣)log∣V∣), the same as bucket construction alone. So for a single one-to-many query against a fresh target set, Bucket-CH offers no advantage. The benefit arises when the target set is fixed, and many queries are issued from different sources against it. The ∣Vt∣|V_t|∣Vt​∣ backward searches are performed once during bucket construction and amortised across all subsequent queries.

Regarding memory, Bucket-CH stores the CH search graph and the buckets: O(∣V∣+∣E′∣+∑v∣B(v)∣)\mathcal{O}(|V| + |E'| + \sum_{v} |\mathcal{B}(v)|)O(∣V∣+∣E′∣+∑v​∣B(v)∣). In road networks, the CH search space is small, but with a large target set, the buckets dominate the memory.

Hub Labeling

Hub Labelling (HL) is a one-to-one pathfinding algorithm. It doesn't require any graph search. HL assigns each vertex vvv a forward label Lf(v)L_f(v)Lf​(v) and a reverse label Lr(v)L_r(v)Lr​(v). It guarantees that for every pair s,ts,ts,t, the intersection Lf(s)∩Lr(t)L_f(s)\cap L_r(t)Lf​(s)∩Lr​(t) contains a hub on the shortest sss-ttt path. A query returns arg⁡min⁡u∈Lf(s)∩Lr(t){τ(s,u)+τ(u,t)}\arg\min_{u\in L_f(s)\cap L_r(t)}\{\tau(s,u)+\tau(u,t)\}argminu∈Lf​(s)∩Lr​(t)​{τ(s,u)+τ(u,t)} without any priority queue or edge relaxations.

Hub Labeling cover property. The intersection $L_f(s)\cap L_r(t)$ contains hub $u_2$; the query returns $\tau(s,u_2)+\tau(u_2,t)$ without any graph search.
Hub Labeling cover property. The intersection $L_f(s)\cap L_r(t)$ contains hub $u_2$; the query returns $\tau(s,u_2)+\tau(u_2,t)$ without any graph search.

The asymptotic complexity of an HL query is the cost of merging two sorted lists: O(∣Lf(s)∣+∣Lr(t)∣)\mathcal{O}(|L_f(s)| + |L_r(t)|)O(∣Lf​(s)∣+∣Lr​(t)∣). There is no priority queue, no edge relaxation, and no graph search. If the average label size is ℓ\ellℓ, queries run in O(ℓ)\mathcal{O}(\ell)O(ℓ) time. This makes HL queries faster than CH on road networks. On walking networks, the speedup is smaller, since walking graphs have a weaker hierarchical structure. The cost of this improvement is increased preprocessing and storage. Computing optimal labels is NP-hard in general, so HL relies on heuristics built on top of an existing CH. Total storage is O(∣V∣⋅ℓ)\mathcal{O}(|V| \cdot \ell)O(∣V∣⋅ℓ), much larger than CH, which stores only O(∣E′∣+∣V∣)\mathcal{O}(|E'| + |V|)O(∣E′∣+∣V∣). On continental road networks, HL needs an order of magnitude more memory than CH.

The asymptotic complexity of HL precomputation is not estimated in the original paper. However, for the standard pruned, CH-based label construction we estimate it as O ⁣(∣V∣⋅∣E∣+∣V∣ℓ2+ℓ∣E∣+∣V∣ℓlog⁡∣V∣)\mathcal{O}\!\left(|V| \cdot |E| + |V|\ell^2 + \ell|E| + |V|\ell \log |V|\right)O(∣V∣⋅∣E∣+∣V∣ℓ2+ℓ∣E∣+∣V∣ℓlog∣V∣), where the ∣V∣ℓ2|V|\ell^2∣V∣ℓ2 term reflects the O(ℓ)\mathcal{O}(\ell)O(ℓ) pruning lookup done at each of the O(∣V∣ℓ)\mathcal{O}(|V|\ell)O(∣V∣ℓ) label entries.

Public Transit Routing

The speed-up techniques above assume two properties that hold on road networks but break down in public transit.

First, edge weights are typically modelled as static. The travel time on a road segment does not depend on when the driver arrives. Time-dependent extensions of CH exist, but the core preprocessing still assumes smooth, slowly changing cost functions. In a transit network, travel times are discrete functions of departure time determined by the timetable. A passenger who arrives at a stop at 8:01 and one who arrives at 8:29 may wait for different vehicles with different running times.

Second, road networks have a hierarchical structure. Roads have different levels of importance: small local roads, national roads, etc. A typical journey trip moves from the bottom of the hierarchy to the top, then back. Transit networks have no such hierarchy. A cross-city transit journey may require a sequence of local buses and useful intermediate stops.

These differences force transit routing algorithms to operate directly on the timetable.

What a transit query actually asks

Before the algorithms, it's worth pinning down what we're even asking for. The central query type in public transit routing is the earliest arrival query: given a source sss, a target ttt, and departure time τdep\tau_{\text{dep}}τdep​, find a journey minimising arrival time at ttt. A practically important generalisation is the multicriteria query, which asks for all Pareto-optimal journeys with respect to arrival time, number of trips, and potentially additional criteria such as walking duration or fare. Another type of query is range queries, which find an optimal route within a time range.

Time-Dependent Dijkstra

Unlike road networks, where edge weights are typically fixed, public transit networks use edge weights that depend on timetables. For each edge e=(v,w)e=(v,w)e=(v,w), the arrival time function fe(τ)=min⁡{τarr∣(τdep,τarr)∈Ce, τdep≥τ}f_e(\tau)=\min\{\tau_{\text{arr}}\mid(\tau_{\text{dep}},\tau_{\text{arr}})\in \mathcal{C}_e,\,\tau_{\text{dep}}\geq\tau\}fe​(τ)=min{τarr​∣(τdep​,τarr​)∈Ce​,τdep​≥τ} maps a departure time τ\tauτ at vvv to the earliest arrival time at www. Time-Dependent Dijkstra (TD-Dijkstra) is a Dijkstra-based one-to-one and one-to-many shortest-path algorithm, which replaces fixed edge costs with arrival time functions evaluated via binary search.

Time-Dependent Dijkstra. (a) Source A is settled at 8:00 and edges A → D and A → E are relaxed by evaluating their timetables, giving $\mathrm{dist}(D)=8{:}10$, $\mathrm{dist}(E)=8{:}11$. (b) Relaxing A → D is a binary search over the connection array for the first departure at or after 8:00, which arrives at 8:10.
Time-Dependent Dijkstra. (a) Source A is settled at 8:00 and edges A → D and A → E are relaxed by evaluating their timetables, giving $\mathrm{dist}(D)=8{:}10$, $\mathrm{dist}(E)=8{:}11$. (b) Relaxing A → D is a binary search over the connection array for the first departure at or after 8:00, which arrives at 8:10.

TD-Dijkstra requires the FIFO property, and that is why filtering of the dominated connections should be applied to it.

The asymptotic complexity of TD-Dijkstra without a Fibonacci heap can be estimated as standard Dijkstra plus binary search over the largest connection set across all edges ∣Cmax⁡∣=max⁡e∣Ce∣|\mathcal{C}_{\max}| = \max_e |\mathcal{C}_e|∣Cmax​∣=maxe​∣Ce​∣. It will be equal to O((∣E∣+∣V∣)log⁡∣V∣+∣E∣log⁡∣Cmax⁡∣)\mathcal{O}\big((|E| + |V|) \log |V| + |E| \log |\mathcal{C}_{\max}|\big)O((∣E∣+∣V∣)log∣V∣+∣E∣log∣Cmax​∣). The first term is the standard Dijkstra cost on the timetable graph. The second comes from the binary search at each edge relaxation. In memory, TD-Dijkstra is plain Dijkstra plus the timetable: O(∣V∣+∣E∣+∣C∣)\mathcal{O}(|V| + |E| + |\mathcal{C}|)O(∣V∣+∣E∣+∣C∣).

A* with the Tung-Chew heuristic

A* works on the transit network too. The catch is the heuristic. Euclidean distance to the target does not work here, because travel time depends on the schedule, not the map. The Tung-Chew heuristic is an option. It came out of a multicriteria Pareto-optimal path algorithm. The idea is simple: we weight every edge by the sum of its criteria, run a search backward from the target, and get the shortest aggregate distance from every node to it.

However, this heuristic is not free, and the cost is all per query. There is no preprocessing, nothing is built once and reused. Building the heuristic is one backward Dijkstra from the target on the reversed graph, and the query itself is an A* search on top of that. Both searches run on the same timetable graph. The total cost is the same order as TD-Dijkstra, and memory is also the same.

RAPTOR and Its Variants

RAPTOR answers single-source earliest-arrival queries to either a fixed target or to all stops simultaneously. In contrast to TD-Dijkstra, it requires the stop-to-stop transfer graph of the public transit network to be transitively closed. The algorithm operates in rounds, where round iii discovers journeys with exactly iii trips by extending journeys from round i−1i-1i−1. For each stop v∈Sv \in \mathcal{S}v∈S and round iii, the arrival time τarr(v,i)\tau_{\text{arr}}(v, i)τarr​(v,i) represents the earliest known arrival at vvv using at most iii trips. A query from source sss with departure time τdep\tau_{\text{dep}}τdep​ initializes τarr(s,0)=τdep\tau_{\text{arr}}(s, 0) = \tau_{\text{dep}}τarr​(s,0)=τdep​ and all other arrival times to ∞\infty∞, then iterates until no improvements occur.

RAPTOR on a three-route network. Round 1 boards Bus 1, reaching transfer stop C at 08:20 and walking to E (08:25). Round 2 reaches the target at 08:55 via Bus 2 and at 09:10 via Bus 3; only 08:55 is Pareto-optimal.
RAPTOR on a three-route network. Round 1 boards Bus 1, reaching transfer stop C at 08:20 and walking to E (08:25). Round 2 reaches the target at 08:55 via Bus 2 and at 09:10 via Bus 3; only 08:55 is Pareto-optimal.

Each round consists of two phases. In the route scanning phase, the algorithm sequentially scans all routes passing through stops improved in the previous round, tracking the earliest boardable trip Tmin⁡T_{\min}Tmin​. At each stop vvv along the route, it checks whether alighting from Tmin⁡T_{\min}Tmin​ improves τarr(v,i)\tau_{\text{arr}}(v, i)τarr​(v,i), and whether an earlier trip becomes boardable. In the transfer relaxation phase, the algorithm relaxes all outgoing edges from improved stops, updating τarr(w,i)\tau_{\text{arr}}(w, i)τarr​(w,i) whenever τarr(v,i)+τtra(e)<τarr(w,i)\tau_{\text{arr}}(v, i) + \tau_{\text{tra}}(e) < \tau_{\text{arr}}(w, i)τarr​(v,i)+τtra​(e)<τarr​(w,i) for edge e=(v,w)e = (v, w)e=(v,w).

Transfer relaxation for a single stop. Stop $p$ has just been settled by the trip scan (Bus 17, arriving 08:30). Relaxation walks the entire footpath adjacency of $p$ and applies $\tau_k(q)\leftarrow\min(\tau_k(q),\tau_k(p)+\ell(p,q))$ to every neighbour $q$.
Transfer relaxation for a single stop. Stop $p$ has just been settled by the trip scan (Bus 17, arriving 08:30). Relaxation walks the entire footpath adjacency of $p$ and applies $\tau_k(q)\leftarrow\min(\tau_k(q),\tau_k(p)+\ell(p,q))$ to every neighbour $q$.

RAPTOR correctly handles buffer times by applying them only when boarding a new trip, not when continuing on the same trip. This is possible because RAPTOR explicitly tracks trip membership during route scanning.

Algorithm: RAPTOR
Require: Timetable (S, T, R, G) with buffer β(p) at each stop p;
         source p_s; target p_t; departure time τ_dep
Ensure:  Pareto-set of journeys to p_t

τ_k(p) ← ∞ for all p, k;  τ_0(p_s) ← τ_dep;  M ← {p_s}
for k = 1, 2, … do
    if M = ∅ then break
    τ_k(p) ← τ_{k-1}(p) for all p
    Build route queue Q from marked stops;  M ← ∅
    for each (r, p) ∈ Q do
        T_min ← ⊥
        for each stop p_i in r from p onward do
            if T_min ≠ ⊥ and τ_arr(T_min, p_i) < min(τ_k(p_i), τ_k(p_t)) then
                τ_k(p_i) ← τ_arr(T_min, p_i);  M ← M ∪ {p_i}
            τ_board ← τ_{k-1}(p_i) + β(p_i)      # transfer waits the buffer
            t' ← earliest trip of r departing p_i at time ≥ τ_board
            if t' departs earlier than T_min then T_min ← t'
    for each p ∈ M, each (p, p') ∈ G do
        if τ_k(p) + τ_tra(p, p') < τ_k(p') then
            τ_k(p') ← τ_k(p) + τ_tra(p, p');  M ← M ∪ {p'}
return { (τ_k(p_t), k) : τ_k(p_t) < ∞ }

The main algorithmic benefit of RAPTOR is that it avoids using a priority queue. Let KKK denote the number of rounds, ∣stops(r)∣|\text{stops}(r)|∣stops(r)∣ the number of stops along route r∈Rr \in \mathcal{R}r∈R, and N:=∑r∈R∣stops(r)∣N := \sum_{r \in \mathcal{R}} |\text{stops}(r)|N:=∑r∈R​∣stops(r)∣ the total route length. Each round runs in O ⁣(N+∣T∣+∣E∣)O\!\left(N + |\mathcal{T}| + |E|\right)O(N+∣T∣+∣E∣) time, since every route and every trip on it is scanned at most once. Over KKK rounds, the worst-case running time is therefore O ⁣(K⋅(N+∣T∣+∣E∣))O\!\left(K \cdot \left(N + |\mathcal{T}| + |E|\right)\right)O(K⋅(N+∣T∣+∣E∣)). In practice, KKK is small, since journeys with many transfers are rare. However, as the transfer distances increase, ∣E∣|E|∣E∣ might grow up to ∣S∣2|\mathcal{S}|^2∣S∣2, since RAPTOR requires the transfer graph to be transitively closed.

RAPTOR doesn't require any algorithmic preprocessing, except for data structure precomputation, and by its architecture optimises two criteria: earliest arrival and transfer amount. It makes it a widely deployed transit routing algorithm, powering OpenTripPlanner, R5, Navitia.io, Solari, and many other systems.

We can estimate its memory as O(N+∣T∣+∣C∣+∣E∣)\mathcal{O}(N + |\mathcal{T}| + |\mathcal{C}| + |E|)O(N+∣T∣+∣C∣+∣E∣), where ∣E∣|E|∣E∣ can reach ∣S∣2|\mathcal{S}|^2∣S∣2 because of the closure. This estimate is equal for all the following modifications of RAPTOR (rRAPTOR, McRAPTOR, BM-RAPTOR).

rRAPTOR. rRAPTOR is a RAPTOR modification for range queries, answering one-to-one or one-to-many queries. Let Ψ\PsiΨ be the set of distinct departure times in the query range. rRAPTOR runs one RAPTOR search for each departure time in Ψ\PsiΨ and returns the union of their Pareto-optimal results, so its query time is O(∣Ψ∣ K(N+∣T∣+∣E∣))O(|\Psi|\,K(N + |\mathcal{T}| + |E|))O(∣Ψ∣K(N+∣T∣+∣E∣)).

rRAPTOR profile. One RAPTOR run is one point; the staircase is the full profile, built by scanning departures latest → earliest and reusing labels.
rRAPTOR profile. One RAPTOR run is one point; the staircase is the full profile, built by scanning departures latest → earliest and reusing labels.

McRAPTOR. McRAPTOR is a one-to-one and one-to-many extension of RAPTOR, which optimises additional criteria beyond arrival time and number of transfers, such as walking duration. Given a set of criteria, a journey JJJ dominates another journey J′J'J′ if JJJ is not worse than J′J'J′ in any criterion.

McRAPTOR keeps a bag of Pareto-optimal labels at each stop instead of RAPTOR's single earliest arrival. Every label trades arrival time against a second criterion (cost). A label is dominated and dropped when another is no later and no more costly.
McRAPTOR keeps a bag of Pareto-optimal labels at each stop instead of RAPTOR's single earliest arrival. Every label trades arrival time against a second criterion (cost). A label is dominated and dropped when another is no later and no more costly.

McRAPTOR replaces each scalar label τk(v)\tau_k(v)τk​(v) with a Pareto bag Bk(v)B_k(v)Bk​(v) of incomparable journeys, whose size is not bounded and depends on both the chosen criteria and the network characteristics. The blow-up is exponential rather than linear in the number of criteria; Pareto sets become impractically large for three or more criteria. Let γ:=max⁡v,k∣Bk(v)∣\gamma := \max_{v,k} |B_k(v)|γ:=maxv,k​∣Bk​(v)∣ be the largest Pareto bag and ddd the number of criteria. Every scan and transfer relaxation becomes a bag merge, each costing O(γd)O(\gamma d)O(γd), giving an overall bound of O ⁣(K γ d (N+∣T∣+∣E∣))O\!\left(K\,\gamma\,d\,(N + |\mathcal{T}| + |E|)\right)O(Kγd(N+∣T∣+∣E∣)). This estimate is only nominal: γ\gammaγ has no polynomial bound and may grow exponentially in ddd.

BM-RAPTOR. BM-RAPTOR keeps only a restricted Pareto set that drops journeys with bad tradeoffs.

BM-RAPTOR. An earliest-arrival RAPTOR first finds the best journey (the anchor). BM-RAPTOR then runs McRAPTOR only inside a slack window around that anchor, discarding any journey past the cutoff, even non-dominated ones.
BM-RAPTOR. An earliest-arrival RAPTOR first finds the best journey (the anchor). BM-RAPTOR then runs McRAPTOR only inside a slack window around that anchor, discarding any journey past the cutoff, even non-dominated ones.

Let J∗\mathcal{J}^{*}J∗ be the set of anchor journeys, Pareto-optimal on arrival time and number of trips alone. A single RAPTOR run produces them. With an arrival-time slack σarr\sigma_{\text{arr}}σarr​ and a trip slack σtr\sigma_{\text{tr}}σtr​, the additive restricted Pareto set is

JR:={ J∈J  ∣  τarr(J)≤τarr(J∗)+σarr  ∧  ∣J∣≤∣J∗∣+σtr }.\mathcal{J}^{R} := \bigl\{\, J \in \mathcal{J} \;\bigm|\; \tau_{\text{arr}}(J) \leq \tau_{\text{arr}}(J^{*}) + \sigma_{\text{arr}} \;\wedge\; |J| \leq |J^{*}| + \sigma_{\text{tr}} \,\bigr\}.JR:={J∈J​τarr​(J)≤τarr​(J∗)+σarr​∧∣J∣≤∣J∗∣+σtr​}.

A multiplicative slack fits passengers better, since a long detour matters more on a long trip than on a short one, relative to the anchor duration τarr(J∗)−τdep\tau_{\text{arr}}(J^{*}) - \tau_{\text{dep}}τarr​(J∗)−τdep​:

JR:={ J∈J  ∣  τarr(J)−τdep≤(τarr(J∗)−τdep)⋅σarr  ∧  ∣J∣≤∣J∗∣⋅σtr }.\mathcal{J}^{R} := \bigl\{\, J \in \mathcal{J} \;\bigm|\; \tau_{\text{arr}}(J) - \tau_{\text{dep}} \leq (\tau_{\text{arr}}(J^{*}) - \tau_{\text{dep}})\cdot\sigma_{\text{arr}} \;\wedge\; |J| \leq |J^{*}|\cdot\sigma_{\text{tr}} \,\bigr\}.JR:={J∈J​τarr​(J)−τdep​≤(τarr​(J∗)−τdep​)⋅σarr​∧∣J∣≤∣J∗∣⋅σtr​}.

BM-RAPTOR runs in three phases. First, a forward RAPTOR runs from the source and gives the anchor journeys and the earliest arrival at the target. Second, a backward RAPTOR runs from the target, marking a superset of the stops that can still reach the target inside the slacks. Third, a McRAPTOR phase builds the restricted set, pruning every label round by round against the arrival-slack bound.

The three phases of BM-RAPTOR: forward RAPTOR (anchors), backward RAPTOR (corridor of stops within the slack), then bounded McRAPTOR inside that corridor, producing the restricted Pareto set.
The three phases of BM-RAPTOR: forward RAPTOR (anchors), backward RAPTOR (corridor of stops within the slack), then bounded McRAPTOR inside that corridor, producing the restricted Pareto set.

Since BM-RAPTOR relies on the forward RAPTOR to the target on the first run, it supports only one-to-one queries. We estimate its complexity as O(KγRd(N+∣T∣+∣E∣))\mathcal{O}(K \gamma_R d (N + |\mathcal{T}| + |E|))O(KγR​d(N+∣T∣+∣E∣)), with the slack-bounded restricted bag γR\gamma_RγR​ in place of the unbounded γ\gammaγ. The restriction buys nothing asymptotically, but in practice it gives a huge speedup: on large metropolitan networks a four-criteria restricted Pareto set can be computed faster by a factor of up to 65, while retaining the important journeys.

Connection Scan Algorithm

The Connection Scan Algorithm (CSA) is a non-graph-based, one-to-one and one-to-many shortest-path algorithm that answers earliest-arrival-time queries in timetable-based information systems. It merges all schedules into a single array of connections C\mathcal{C}C sorted by departure time. It runs a single binary search for the closest connection to the departure time from the source, then sequentially scans through the following valid connections, updating the arrival time for each station. The process stops once it encounters a connection whose departure time exceeds the target station's earliest arrival time. CSA requires the transitive closure of the transfer graph and correctly handles the buffer in the same way as RAPTOR.

Algorithm: Connection Scan Algorithm (CSA)
Require: Connections C sorted by τ_dep; source s; target t; departure time τ_dep
Ensure:  Earliest arrival at t

τ[v] ← ∞ for all v;  τ[s] ← τ_dep;  R[·] ← false
for each c ∈ C in order do
    if τ_dep(c) > τ[t] then break
    if R[T_c] or τ[v_dep(c)] + β(v_dep(c)) ≤ τ_dep(c) then
        R[T_c] ← true
        if τ_arr(c) < τ[v_arr(c)] then
            τ[v_arr(c)] ← τ_arr(c)
            for each footpath f from v_arr(c) do
                τ[f_arr] ← min(τ[f_arr], τ_arr(c) + τ_tra(f))
return τ[t]

CSA runs the search over the sorted list of connections, visiting each connection at most once. This gives a worst-case per-query running time of O(∣C∣+∣E∣)O(|\mathcal{C}| + |E|)O(∣C∣+∣E∣), where ∣C∣|\mathcal{C}|∣C∣ is the total number of connections. Preprocessing is just a single sort of all connections by departure time, O(∣C∣log⁡∣C∣)O(|\mathcal{C}| \log |\mathcal{C}|)O(∣C∣log∣C∣). CSA's performance lies in constant-factor efficiency: each connection is processed via a few array lookups rather than priority-queue operations. However, the framework doesn't scale well for multicriteria search; the multicriteria version, MCSA, is significantly slower than McRAPTOR.

CSA stores the sorted connection array and the closed transfer graph: O(∣C∣+∣E∣)\mathcal{O}(|\mathcal{C}| + |E|)O(∣C∣+∣E∣), where ∣E∣|E|∣E∣ can reach up to ∣S∣2|\mathcal{S}|^2∣S∣2 because of the closure.

Trip-Based Routing (TB)

Trip-Based Routing (TB) is a one-to-one journey planning algorithm. TB uses trips as its fundamental building block. Each trip is labelled with the stops at which it can be boarded. A precomputed list of transfers to other trips is then scanned, and newly reached trips are labelled. When a trip reaches the destination, a journey is added to the result set. Structurally, this is a breadth-first traversal of trip segments connected by a precomputed transfer set Es⊆E×EE^s \subseteq \mathcal{E} \times \mathcal{E}Es⊆E×E. Like RAPTOR, TB operates in rounds, but scans individual trip segments rather than entire routes. In practice, TB outperforms RAPTOR on two-criteria queries (arrival time and number of transfers), at the cost of this preprocessing step.

Trip-Based Routing. (a) Three trips on horizontal lanes; precomputed transfers are vertical arrows at shared stops. (b) BFS query: $T_1$ boards at the source ($Q_0$); its transfers add $T_2$ (via A) and $T_3$ (via B) to $Q_1$; $T_3$ reaches the target, yielding a one-transfer journey. Trips carry a label $R(t)$ (first reached stop), not a time; no priority queue is needed.
Trip-Based Routing. (a) Three trips on horizontal lanes; precomputed transfers are vertical arrows at shared stops. (b) BFS query: $T_1$ boards at the source ($Q_0$); its transfers add $T_2$ (via A) and $T_3$ (via B) to $Q_1$; $T_3$ reaches the target, yielding a one-transfer journey. Trips carry a label $R(t)$ (first reached stop), not a time; no priority queue is needed.

We estimate the worst-case query as O(K⋅(∣C∣+∣Es∣))O(K \cdot (|\mathcal{C}| + |E^s|))O(K⋅(∣C∣+∣Es∣)), where ∣C∣|\mathcal{C}|∣C∣ is the total number of elementary connections and ∣Es∣|E^s|∣Es∣ is the size of the preprocessed transfer set. The size of EsE^sEs is reduced by two heuristic rules (U-turn elimination and transfer-replacement reduction) whose effect depends on the network. We estimate the preprocessing cost as O(N dˉE ρ)O(N\,\bar{d}_E\,\rho)O(NdˉE​ρ), where dˉE=∣E∣/∣S∣\bar{d}_E = |E|/|\mathcal{S}|dˉE​=∣E∣/∣S∣ is the average number of transfer edges per stop and ρ\rhoρ bounds the trips boardable at a stop.

TB requires the transitive closure of the transfer graph and was originally evaluated only for sparse transfer graphs; it does not support unrestricted transfer graphs. A later variant using Condensed Search Trees drops the transitive-closure requirement and reaches microsecond-scale queries, but increases preprocessing overhead by up to an order of magnitude. TB's memory is estimated as O(∣C∣+∣Es∣)\mathcal{O}(|\mathcal{C}| + |E^s|)O(∣C∣+∣Es∣).

Transfer Patterns

Transfer Patterns is a one-to-one shortest-path algorithm originally developed at Google for Google Maps, based on the observation that many optimal journeys between a given origin and destination share the same sequence of transfer stops. The technique precomputes, for each pair of stops, the set of transfer stop sequences appearing in optimal journeys, so queries can be answered by searching only within these patterns.

The precomputation is heavy. The original paper estimates the total number of settled labels as L=λ mˉ ∣S∣2L = \lambda\,\bar{m}\,|\mathcal{S}|^2L=λmˉ∣S∣2, quadratic in the number of stations. Scalable Transfer Patterns reduces it by roughly three orders of magnitude by adding frequency-based profile labels that exploit the timetable's periodicity. We re-express the original estimate as L=Θ(γ ∣E∣ ∣S∣)L = \Theta(\gamma\,|\mathcal{E}|\,|\mathcal{S}|)L=Θ(γ∣E∣∣S∣).

A query first assembles the precomputed transfer patterns for the source–target pair into a small directed acyclic query-graph (DAG), then runs a time-dependent multi-criteria Dijkstra search on it. We estimate the query cost as O(γ qlog⁡q+q Cdc)O(\gamma\,q\log q + q\,C_{\text{dc}})O(γqlogq+qCdc​), where qqq is the query-graph size, γ\gammaγ the Pareto-bag size, and Cdc=O(log⁡∣T∣)C_{\text{dc}} = O(\log|\mathcal{T}|)Cdc​=O(log∣T∣) the cost of a single direct-connection query. Crucially, qqq depends only on the pattern count of the queried pair, so query time is independent of network size. The memory can be O(γ ∣E∣ ∣S∣)\mathcal{O}(\gamma\,|\mathcal{E}|\,|\mathcal{S}|)O(γ∣E∣∣S∣); this quadratic storage is the main weakness.

Unlimited Transfer and Multimodal Routing

Public transit algorithms such as CSA, RAPTOR and TB require the transfer graph to be transitively closed, which becomes the primary bottleneck for large transfer radii. Many papers claim that reducing walking distances is beneficial because people usually prefer not to walk long distances, and that it doesn't affect travel time in practice. However, Wagner and Zündorf demonstrated practical applications of long-distance transfer and the fact that fully multimodal paths usually have an earlier arrival time. The median difference during nighttime on the German network was around 2 hours; even during the daytime, 75% of queries with transfer reduction return non-optimal paths. They also showed that limiting walking to 20 minutes already produces a graph too large for practical use, yet removing restrictions substantially reduces travel times.

From here on, every algorithm works with the full transfer graph and drops the transitive-closure requirement — which is exactly what makes unlimited transfers practical.

Core-CH

In multimodal pathfinding, the transfer graph is used only for initial transfers from the source to a boarding stop, intermediate transfers between trips, and final transfers to the target. As a result, at query time, the algorithm doesn't need to search the full transfer graph, only the pairwise distances between stops. Core-CH provides these efficiently by precomputing a small core graph that keeps the stops while contracting away the rest of the transfer graph. It iteratively contracts non-stop vertices S∗=V∖S\mathcal{S}^* = V \setminus \mathcal{S}S∗=V∖S in standard CH order. The process stops once the average vertex degree of the core graph crosses a specified threshold.

Core-CH preprocessing. (a) Original graph with stops $p, p'$ (never contracted) and road nodes $v_1,\dots,v_5$. (b) After contracting all non-stop vertices, only stops remain in the core, connected by shortcut edges that preserve all pairwise stop-to-stop distances.
Core-CH preprocessing. (a) Original graph with stops $p, p'$ (never contracted) and road nodes $v_1,\dots,v_5$. (b) After contracting all non-stop vertices, only stops remain in the core, connected by shortcut edges that preserve all pairwise stop-to-stop distances.

Core-CH performs the same CH precomputation, but interrupts it when it crosses a specified threshold. Its preprocessing cost is therefore bounded above by full CH, O(∣V∣⋅∣E∣)\mathcal{O}(|V| \cdot |E|)O(∣V∣⋅∣E∣). At query time, it runs the same bidirectional Dijkstra on the augmented graph. This architecture allows us, in practice, to generate longer first and last miles, which might represent longer transfer legs, where the user may take a taxi to the transit network or reach out from it to the target stop.

First and last mile in Core-CH: an upward Dijkstra for the first mile from source $s$ (e.g. by taxi) into the core, and a reverse upward search for the last mile from the core to target $t$.
First and last mile in Core-CH: an upward Dijkstra for the first mile from source $s$ (e.g. by taxi) into the core, and a reverse upward search for the last mile from the core to target $t$.

In memory, Core-CH is the same form as CH: it stores the augmented graph, O(∣V∣+∣E′∣)\mathcal{O}(|V| + |E'|)O(∣V∣+∣E′∣). Because it stops the contraction once the core gets too dense, it adds fewer shortcuts than a full CH.

MR

MR (originally MR-∞) uses the Core-CH concept in its search and extends RAPTOR by replacing local transfer relaxation with Dijkstra's algorithm on the Core-CH graph. MR initialises the priority queue with all stops marked in the current round, then runs a single multi-source Dijkstra search, settling every reachable core vertex and marking any stop reached. Initial and final transfers are handled separately via upward and downward searches from the source and target vertices.

Transfer relaxation in RAPTOR versus MR. RAPTOR (left) relaxes a precomputed footpath list and requires the footpath graph to be transitively closed. MR (right) runs a multi-source Dijkstra from all marked stops over the contracted core graph; no transitive closure is needed.
Transfer relaxation in RAPTOR versus MR. RAPTOR (left) relaxes a precomputed footpath list and requires the footpath graph to be transitively closed. MR (right) runs a multi-source Dijkstra from all marked stops over the contracted core graph; no transitive closure is needed.

We estimate MR as standard RAPTOR complexity plus Dijkstra on the core graph Go=(Vo,Eo)G^o = (V^o, E^o)Go=(Vo,Eo): O ⁣(K⋅(N+∣T∣+(∣Eo∣+∣Vo∣)log⁡∣Vo∣))O\!\left(K \cdot \left(N + |\mathcal{T}| + (|E^o| + |V^o|) \log |V^o|\right)\right)O(K⋅(N+∣T∣+(∣Eo∣+∣Vo∣)log∣Vo∣)). MR search performs faster than RAPTOR when (∣Eo∣+∣Vo∣)log⁡∣Vo∣<∣S∣2(|E^o| + |V^o|) \log |V^o| < |\mathcal{S}|^2(∣Eo∣+∣Vo∣)log∣Vo∣<∣S∣2, meaning the transitive closure becomes too dense and RAPTOR's transfer phase, which scans up to O(∣S∣2)O(|\mathcal{S}|^2)O(∣S∣2) closure edges per round, becomes very slow. MR doesn't require timetable-dependent preprocessing; its total memory is O(N+∣T∣+∣C∣+∣Vo∣+∣Eo∣)\mathcal{O}(N + |\mathcal{T}| + |\mathcal{C}| + |V^o| + |E^o|)O(N+∣T∣+∣C∣+∣Vo∣+∣Eo∣).

MCR

MCR is the multicriteria version of MR. It extends the search to additional criteria beyond arrival time and number of trips, such as walking duration or costs. Its complexity is the same as McRAPTOR, with the transfer search over the transitively closed graph replaced by a Dijkstra run on the core graph GoG^oGo: O ⁣(Kγd(N+∣T∣+(∣Eo∣+∣Vo∣)log⁡∣Vo∣))O\!\left(K \gamma d \left(N + |\mathcal{T}| + (|E^o| + |V^o|) \log |V^o|\right)\right)O(Kγd(N+∣T∣+(∣Eo∣+∣Vo∣)log∣Vo∣)). It stores the same data structure as MR and does not need timetable-dependent preprocessing.

Hub Labelling for Unlimited Transfers

Phan and Viennot applied Hub Labelling to the transfer graph in both RAPTOR and CSA to accelerate unlimited-transfer routing without running a Dijkstra search in each round. They report a 1.7×1.7\times1.7× speedup over MR on the London dataset for HL-RAPTOR. However, this claim was based solely on copying the number from the MR paper and hasn't been properly tested on the same machine with the same query set. This gap was later addressed in the literature, showing that the actual performance is much lower.

We estimate the per-round transfer phase of HL-RAPTOR as O(∣S∣⋅ℓ2)O(|\mathcal{S}| \cdot \ell^2)O(∣S∣⋅ℓ2) in the worst case, giving O ⁣(K⋅(N+∣T∣+∣S∣⋅ℓ2))O\!\left(K \cdot \left(N + |\mathcal{T}| + |\mathcal{S}| \cdot \ell^2\right)\right)O(K⋅(N+∣T∣+∣S∣⋅ℓ2)). The analogous bound for HL-CSA is O(∣C∣+∣S∣⋅ℓ2)O(|\mathcal{C}| + |\mathcal{S}| \cdot \ell^2)O(∣C∣+∣S∣⋅ℓ2). HL-RAPTOR is faster than RAPTOR when ℓ2<∣S∣\ell^2 < |\mathcal{S}|ℓ2<∣S∣, which is valid for the unlimited transfer problem. In memory, HL-RAPTOR is O(N+∣T∣+∣C∣+∣S∣⋅ℓ)\mathcal{O}(N + |\mathcal{T}| + |\mathcal{C}| + |\mathcal{S}| \cdot \ell)O(N+∣T∣+∣C∣+∣S∣⋅ℓ) and HL-CSA is O(∣C∣+∣S∣⋅ℓ)\mathcal{O}(|\mathcal{C}| + |\mathcal{S}| \cdot \ell)O(∣C∣+∣S∣⋅ℓ).

ULTRA

Stop-level shortcuts

ULTRA is, for now, the main state-of-the-art framework for unlimited transfers. Rather than computing the full transitive closure, ULTRA precomputes only the shortcut edges representing transfers in Pareto-optimal journeys. For initial and final transfers, ULTRA uses Bucket-CH one-to-many searches across the full street network, which significantly accelerates the search process.

ULTRA concept. Without ULTRA (left): unlimited transfers require a transitively closed footpath graph with $O(n^2)$ edges. With ULTRA (right): preprocessing stores only the shortcuts appearing in Pareto-optimal journeys; dominated transfers (×) are discarded. At query time any algorithm (RAPTOR, CSA) uses the shortcuts as one-hop transfers; initial and final transfers are handled by Bucket-CH.
ULTRA concept. Without ULTRA (left): unlimited transfers require a transitively closed footpath graph with $O(n^2)$ edges. With ULTRA (right): preprocessing stores only the shortcuts appearing in Pareto-optimal journeys; dominated transfers (×) are discarded. At query time any algorithm (RAPTOR, CSA) uses the shortcuts as one-hop transfers; initial and final transfers are handled by Bucket-CH.

For each source stop s∈Ss \in \mathcal{S}s∈S, ULTRA runs rRAPTOR restricted to two rounds (canonical MR), with transfers relaxed by Dijkstra on a contracted core graph Go=(Vo,Eo)G^o = (V^o, E^o)Go=(Vo,Eo). The total complexity of ULTRA preprocessing is O(∣S∣ (∣Eo∣+∣Vo∣)log⁡∣Vo∣+(∑s∣Ψs∣) (N+∣T∣+(∣Eo∣+∣Vo∣)log⁡∣Vo∣))O\bigl(|\mathcal{S}|\,(|E^o| + |V^o|) \log |V^o| + (\sum_{s} |\Psi_s|)\,(N + |\mathcal{T}| + (|E^o| + |V^o|) \log |V^o|)\bigr)O(∣S∣(∣Eo∣+∣Vo∣)log∣Vo∣+(∑s​∣Ψs​∣)(N+∣T∣+(∣Eo∣+∣Vo∣)log∣Vo∣)).

In practice, the original paper reports preprocessing times of roughly 9 minutes for Switzerland and around 8 hours for Germany. The preprocessing is performed once per timetable and amortised across all subsequent queries. This makes ULTRA unsuitable for online use where the timetable changes frequently. These shortcuts are timetable-dependent; independently of them, ULTRA builds a Bucket-CH for the initial and final transfers that remains valid across schedule changes. Combined with Bucket-CH, classical algorithms like CSA and RAPTOR can run on these shortcuts to find multimodal paths, achieving up to a 3×3\times3× speedup over MR and HL-RAPTOR.

In memory, ULTRA stores the stop-level shortcut set EscE_{\text{sc}}Esc​ and the Bucket-CH: O(∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)\mathcal{O}(|E_{\text{sc}}| + |V| + |E'| + \sum_{v} |\mathcal{B}(v)|)O(∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣).

Multicriteria stop-level shortcuts

With unlimited transfers, optimising only arrival time and the number of trips is not enough. A journey optimal on those two criteria can spend a long time walking, while a journey arriving slightly later walks far less. McULTRA is a three-criteria extension of ULTRA that adds transfer time as a third criterion. The shortcut computation keeps the ULTRA structure, but enumerates journeys with McRAPTOR instead of RAPTOR and relaxes transfers with a multi-criteria Dijkstra.

By adding the third criterion, the number of stop-level shortcuts grows less than a factor of two, and the preprocessing time is roughly two to four times slower than two-criterion ULTRA. For comparison, three-criterion MCR is about twenty times slower than MR, meaning the shortcut approach scales much better. We call the version that runs on multicriteria shortcuts ULTRA-McRAPTOR, and the bounded variant UBM-RAPTOR. We estimate the shortcut precomputation by adding an O(γd)O(\gamma d)O(γd) factor on top of stop-level ULTRA. In memory, it has the same form as stop-level ULTRA.

Event-level shortcuts

An alternative version of ULTRA was developed for TB. Since TB indexes transfers between stop events rather than between stops, the ULTRA preprocessing was adapted to produce event-level shortcuts. The adaptation keeps the ULTRA journey enumeration but produces time-dependent shortcuts under strict domination. We estimate its asymptotic complexity as the same as stop-level ULTRA, differing only in constant factors and in the output, which is the larger event-level shortcut set Esc\mathcal{E}_{\text{sc}}Esc​. With TB on top, the memory usage is O(∣C∣+∣T∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)\mathcal{O}(|\mathcal{C}| + |\mathcal{T}| + |\mathcal{E}_{\text{sc}}| + |V| + |E'| + \sum_{v} |\mathcal{B}(v)|)O(∣C∣+∣T∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣).

Delay-ULTRA

Algorithms without timetable-dependent preprocessing, like MR, HL-RAPTOR, and HL-CSA, are inherently delay-robust. The ULTRA framework uses timetable information in its preprocessing step and, as a result, is not robust to delays.

DB-ULTRA introduced unannotated stop-level shortcuts valid for any delay scenario within a fixed buffer Δ\DeltaΔ. The shortcut count grows rapidly under the Delay-All model (over twelve million at Δ=30\Delta = 30Δ=30 min on Switzerland), which motivated annotating shortcuts with delay sub-intervals and adapting the framework to TB. D-ULTRA computes shortcuts at the event level: each shortcut (εa,εb)∈Esc(\varepsilon_a, \varepsilon_b) \in \mathcal{E}_{\text{sc}}(εa​,εb​)∈Esc​ connects two specific stop events and carries a delay interval. This granularity is natural for TB, which indexes transfers by stop event, but it is incompatible with CSA and RAPTOR, which index transfers by stop.

Delay-ULTRA-TB. Phase 1 (offline): ULTRA shortcut computation with a delay bound $\Delta$ yields a compact set $\mathcal{E}_{\text{sc}}$ sufficient for delays up to $\Delta$. Phase 2 (seconds): on a delay update, infeasible shortcuts are discarded and a heuristic replacement search adds missing ones, producing $\mathcal{E}_{\text{sc}}'$. Phase 3 (milliseconds): the query runs TB on $\mathcal{E}_{\text{sc}}'$.
Delay-ULTRA-TB. Phase 1 (offline): ULTRA shortcut computation with a delay bound $\Delta$ yields a compact set $\mathcal{E}_{\text{sc}}$ sufficient for delays up to $\Delta$. Phase 2 (seconds): on a delay update, infeasible shortcuts are discarded and a heuristic replacement search adds missing ones, producing $\mathcal{E}_{\text{sc}}'$. Phase 3 (milliseconds): the query runs TB on $\mathcal{E}_{\text{sc}}'$.

The offline computation is basically the ULTRA enumeration, run in best-case delay scenarios, splitting the work by origin stop prefix and running two witness searches per subproblem instead of one. We estimate its complexity as the same as ULTRA preprocessing; the only differences are a constant factor and the output, which is the event-level shortcut set with a delay interval attached to each shortcut. With TB on top, the total memory is O(∣C∣+∣T∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)\mathcal{O}(|\mathcal{C}| + |\mathcal{T}| + |\mathcal{E}_{\text{sc}}| + |V| + |E'| + \sum_{v} |\mathcal{B}(v)|)O(∣C∣+∣T∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣).

Animated walkthrough of fast, memory-efficient multimodal journey planning under delays: a delay hits a service, infeasible shortcuts are dropped, and a recovery query reaches the destination on time.
Delay-aware routing in motion: when a service slips, infeasible shortcuts drop out and a recovery query still reaches the destination on time.

So which one should you use?

We've covered a lot of ground — three worlds, really: road network routing, public transit routing, and multimodal routing with unrestricted transfers. There's no single winner. Each makes different assumptions about the input, and the right pick is always a trade-off among preprocessing cost, query speed, and how well it copes with a timetable that keeps changing under you.

Road network algorithms exploit hierarchy and static edge weights to enable sub-millisecond query times on continental graphs. Contraction Hierarchies and Hub Labelling are the main state-of-the-art solutions, with HL trading additional memory for the fastest query times. Bucket-CH extends CH to one-to-many queries, which is useful in multimodal routing.

Public transit algorithms operate directly on the timetable. CSA provides the fastest earliest-arrival query response with the minimum preprocessing cost. RAPTOR is a good choice for multicriteria search and needs no preprocessing beyond data-structure construction. TB outperforms RAPTOR on multi-criteria queries but requires preprocessing. Transfer Patterns push this trade-off further, achieving microsecond query times through heavy precomputation. CSA, RAPTOR, and TB require a transitively closed transfer graph, which makes them hard to scale to multimodal pathfinding over arbitrary transfer distances.

The unlimited-transfer setting splits into two families. The first (MR, HL-RAPTOR, HL-CSA) preprocesses only the transfer graph and therefore remains valid across timetable changes and delays. The second (ULTRA) precomputes shortcuts that depend on the schedule. It achieves the fastest query times among unlimited-transfer algorithms, but may lose validity when the schedule changes. Delay-ULTRA partially addresses this by precalculating the needed shortcuts within a constant delay and adding an online update phase, but it can't guarantee solution optimality.

If you want the whole picture on one screen, here are the two cheat-sheets — what each algorithm stores, and how fast it answers. (All the memory and preprocessing bounds below are our own estimates; most of the original papers never state one.)

Stored data-structure memory

AlgorithmPreprocessing timeClosureMemory (data structure)
DijkstranonenoO(∣V∣+∣E∣)O(\lvert V\rvert + \lvert E\rvert)O(∣V∣+∣E∣)
A*nonenoO(∣V∣+∣E∣)O(\lvert V\rvert + \lvert E\rvert)O(∣V∣+∣E∣)
Bi-Dijkstra (CH)O(∣V∣⋅∣E∣)O(\lvert V\rvert\cdot\lvert E\rvert)O(∣V∣⋅∣E∣)noO(∣V∣+∣E′∣)O(\lvert V\rvert + \lvert E'\rvert)O(∣V∣+∣E′∣)
Bucket-CHO(∣V∣∣E∣+∣Vt∣(∣E′∣+∣V∣)log⁡∣V∣)O(\lvert V\rvert\lvert E\rvert + \lvert V_t\rvert(\lvert E'\rvert+\lvert V\rvert)\log\lvert V\rvert)O(∣V∣∣E∣+∣Vt​∣(∣E′∣+∣V∣)log∣V∣)noO(∣V∣+∣E′∣+∑v∣B(v)∣)O(\lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(∣V∣+∣E′∣+∑v​∣B(v)∣)
Hub LabellingO(∣V∣∣E∣+∣V∣ℓ2+ℓ∣E∣+∣V∣ℓlog⁡∣V∣)O(\lvert V\rvert\lvert E\rvert + \lvert V\rvert\ell^2 + \ell\lvert E\rvert + \lvert V\rvert\ell\log\lvert V\rvert)O(∣V∣∣E∣+∣V∣ℓ2+ℓ∣E∣+∣V∣ℓlog∣V∣)noO(∣V∣ ℓ)O(\lvert V\rvert\,\ell)O(∣V∣ℓ)
TD-Dijkstra—noO(∣V∣+∣E∣+∣C∣)O(\lvert V\rvert + \lvert E\rvert + \lvert\mathcal{C}\rvert)O(∣V∣+∣E∣+∣C∣)
A* (Tung-Chew)—noO(∣V∣+∣E∣+∣C∣)O(\lvert V\rvert + \lvert E\rvert + \lvert\mathcal{C}\rvert)O(∣V∣+∣E∣+∣C∣)
RAPTOR—yesO(N+∣T∣+∣C∣+∣E∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E\rvert)O(N+∣T∣+∣C∣+∣E∣)
rRAPTOR—yesO(N+∣T∣+∣C∣+∣E∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E\rvert)O(N+∣T∣+∣C∣+∣E∣)
McRAPTOR—yesO(N+∣T∣+∣C∣+∣E∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E\rvert)O(N+∣T∣+∣C∣+∣E∣)
BM-RAPTOR—yesO(N+∣T∣+∣C∣+∣E∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E\rvert)O(N+∣T∣+∣C∣+∣E∣)
CSAO(∣C∣log⁡∣C∣)O(\lvert\mathcal{C}\rvert\log\lvert\mathcal{C}\rvert)O(∣C∣log∣C∣)yesO(∣C∣+∣E∣)O(\lvert\mathcal{C}\rvert + \lvert E\rvert)O(∣C∣+∣E∣)
TBO(N dˉE ρ)O(N\,\bar{d}_E\,\rho)O(NdˉE​ρ)yesO(∣C∣+∣Es∣)O(\lvert\mathcal{C}\rvert + \lvert E^s\rvert)O(∣C∣+∣Es∣)
Transfer PatternsΘ(γ∣E∣∣S∣)\Theta(\gamma\lvert\mathcal{E}\rvert\lvert\mathcal{S}\rvert)Θ(γ∣E∣∣S∣) labelsnoO(γ ∣E∣ ∣S∣)O(\gamma\,\lvert\mathcal{E}\rvert\,\lvert\mathcal{S}\rvert)O(γ∣E∣∣S∣)
MRCore-CHnoO(N+∣T∣+∣C∣+∣Vo∣+∣Eo∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert V^o\rvert + \lvert E^o\rvert)O(N+∣T∣+∣C∣+∣Vo∣+∣Eo∣)
MCRCore-CHnoO(N+∣T∣+∣C∣+∣Vo∣+∣Eo∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert V^o\rvert + \lvert E^o\rvert)O(N+∣T∣+∣C∣+∣Vo∣+∣Eo∣)
HL-RAPTORHLnoO(N+∣T∣+∣C∣+∣S∣ℓ)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert\mathcal{S}\rvert\ell)O(N+∣T∣+∣C∣+∣S∣ℓ)
HL-CSACSA + HLnoO(∣C∣+∣S∣ℓ)O(\lvert\mathcal{C}\rvert + \lvert\mathcal{S}\rvert\ell)O(∣C∣+∣S∣ℓ)
ULTRA-RAPTORULTRA (stop) + Core-CH + Bucket-CHnoO(N+∣T∣+∣C∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E_{\text{sc}}\rvert + \lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(N+∣T∣+∣C∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣)
ULTRA-CSAULTRA (stop) + Core-CH + Bucket-CHnoO(∣C∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)O(\lvert\mathcal{C}\rvert + \lvert E_{\text{sc}}\rvert + \lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(∣C∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣)
ULTRA-TBULTRA (event) + Core-CH + Bucket-CHnoO(∣C∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)O(\lvert\mathcal{C}\rvert + \lvert\mathcal{E}_{\text{sc}}\rvert + \lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(∣C∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣)
ULTRA-McRAPTORMcULTRA (stop) + Core-CH + Bucket-CHnoO(N+∣T∣+∣C∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E_{\text{sc}}\rvert + \lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(N+∣T∣+∣C∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣)
UBM-RAPTORMcULTRA (stop) + Core-CH + Bucket-CHnoO(N+∣T∣+∣C∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)O(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{C}\rvert + \lvert E_{\text{sc}}\rvert + \lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(N+∣T∣+∣C∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣)
Delay-ULTRA-TBDelay-ULTRA + Core-CH + Bucket-CHnoO(∣C∣+∣Esc∣+∣V∣+∣E′∣+∑v∣B(v)∣)O(\lvert\mathcal{C}\rvert + \lvert\mathcal{E}_{\text{sc}}\rvert + \lvert V\rvert + \lvert E'\rvert + \sum_v\lvert\mathcal{B}(v)\rvert)O(∣C∣+∣Esc​∣+∣V∣+∣E′∣+∑v​∣B(v)∣)

Memory bounds are our estimates; none of the original papers state one. These bounds count only what each algorithm keeps in memory between queries; per-query working memory is excluded.

Query algorithms and query-time complexity

AlgorithmProblemCriteriaQuery typeQuery timeStable
Dijkstraroadgeneralized cost1-to-1 / 1-to-nnnO((∣E∣+∣V∣)log⁡∣V∣)O((\lvert E\rvert+\lvert V\rvert)\log\lvert V\rvert)O((∣E∣+∣V∣)log∣V∣)—
A*roadgeneralized cost1-to-1O((∣E∣+∣V∣)log⁡∣V∣)O((\lvert E\rvert+\lvert V\rvert)\log\lvert V\rvert)O((∣E∣+∣V∣)log∣V∣)—
Bi-Dijkstra (CH)roadgeneralized cost1-to-1O((∣E′∣+∣V∣)log⁡∣V∣)O((\lvert E'\rvert+\lvert V\rvert)\log\lvert V\rvert)O((∣E′∣+∣V∣)log∣V∣)—
Bucket-CHroadgeneralized cost1-to-nnnO((∣E′∣+∣V∣)log⁡∣V∣+∑v∈F(s)∣B(v)∣)O((\lvert E'\rvert+\lvert V\rvert)\log\lvert V\rvert + \sum_{v\in\mathcal{F}(s)}\lvert\mathcal{B}(v)\rvert)O((∣E′∣+∣V∣)log∣V∣+∑v∈F(s)​∣B(v)∣)—
Hub Labellingroadgeneralized cost1-to-1O(ℓ)O(\ell)O(ℓ)—
TD-Dijkstratransitτarr\tau_{\text{arr}}τarr​1-to-1 / 1-to-nnnO((∣E∣+∣V∣)log⁡∣V∣+∣E∣log⁡∣Cmax⁡∣)O((\lvert E\rvert+\lvert V\rvert)\log\lvert V\rvert + \lvert E\rvert\log\lvert C_{\max}\rvert)O((∣E∣+∣V∣)log∣V∣+∣E∣log∣Cmax​∣)yes
A* (Tung-Chew)transitgeneralized cost1-to-1O((∣E∣+∣V∣)log⁡∣V∣+∣E∣log⁡∣Cmax⁡∣)O((\lvert E\rvert+\lvert V\rvert)\log\lvert V\rvert + \lvert E\rvert\log\lvert C_{\max}\rvert)O((∣E∣+∣V∣)log∣V∣+∣E∣log∣Cmax​∣)yes
RAPTORtransitτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1 / 1-to-nnnO(K(N+∣T∣+∣E∣))O(K(N + \lvert\mathcal{T}\rvert + \lvert E\rvert))O(K(N+∣T∣+∣E∣))yes
rRAPTORtransitτarr,K\tau_{\text{arr}}, Kτarr​,K, range1-to-1 / 1-to-nnnO(∣Ψ∣ K(N+∣T∣+∣E∣))O(\lvert\Psi\rvert\,K(N + \lvert\mathcal{T}\rvert + \lvert E\rvert))O(∣Ψ∣K(N+∣T∣+∣E∣))yes
McRAPTORtransitτarr,K\tau_{\text{arr}}, Kτarr​,K, ext.1-to-1 / 1-to-nnnO(Kγd(N+∣T∣+∣E∣))O(K\gamma d(N + \lvert\mathcal{T}\rvert + \lvert E\rvert))O(Kγd(N+∣T∣+∣E∣))yes
BM-RAPTORtransitτarr,K\tau_{\text{arr}}, Kτarr​,K, ext., bnd.1-to-1O(KγRd(N+∣T∣+∣E∣))O(K\gamma_R d(N + \lvert\mathcal{T}\rvert + \lvert E\rvert))O(KγR​d(N+∣T∣+∣E∣))yes
CSAtransitτarr\tau_{\text{arr}}τarr​1-to-1 / 1-to-nnnO(∣C∣+∣E∣)O(\lvert\mathcal{C}\rvert + \lvert E\rvert)O(∣C∣+∣E∣)re-sort
TBtransitτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1O(K(∣C∣+∣Es∣))O(K(\lvert\mathcal{C}\rvert + \lvert E^s\rvert))O(K(∣C∣+∣Es∣))no
Transfer Patternstransitτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1O(γqlog⁡q+q Cdc)O(\gamma q\log q + q\,C_{\text{dc}})O(γqlogq+qCdc​)no
MRmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1 / 1-to-nnnO(K(N+∣T∣+(∣Eo∣+∣Vo∣)log⁡∣Vo∣))O(K(N + \lvert\mathcal{T}\rvert + (\lvert E^o\rvert+\lvert V^o\rvert)\log\lvert V^o\rvert))O(K(N+∣T∣+(∣Eo∣+∣Vo∣)log∣Vo∣))yes
MCRmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K, ext.1-to-1 / 1-to-nnnO(Kγd(N+∣T∣+(∣Eo∣+∣Vo∣)log⁡∣Vo∣))O(K\gamma d(N + \lvert\mathcal{T}\rvert + (\lvert E^o\rvert+\lvert V^o\rvert)\log\lvert V^o\rvert))O(Kγd(N+∣T∣+(∣Eo∣+∣Vo∣)log∣Vo∣))yes
HL-RAPTORmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1 / 1-to-nnnO(K(N+∣T∣+∣S∣ℓ2))O(K(N + \lvert\mathcal{T}\rvert + \lvert\mathcal{S}\rvert\ell^2))O(K(N+∣T∣+∣S∣ℓ2))yes
HL-CSAmultimodalτarr\tau_{\text{arr}}τarr​1-to-1 / 1-to-nnnO(∣C∣+∣S∣ℓ2)O(\lvert\mathcal{C}\rvert + \lvert\mathcal{S}\rvert\ell^2)O(∣C∣+∣S∣ℓ2)yes
ULTRA-RAPTORmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1 / 1-to-nnnO(K(N+∣T∣+∣Esc∣))O(K(N + \lvert\mathcal{T}\rvert + \lvert E_{\text{sc}}\rvert))O(K(N+∣T∣+∣Esc​∣))no
ULTRA-CSAmultimodalτarr\tau_{\text{arr}}τarr​1-to-1 / 1-to-nnnO(∣C∣+∣Esc∣)O(\lvert\mathcal{C}\rvert + \lvert E_{\text{sc}}\rvert)O(∣C∣+∣Esc​∣)no
ULTRA-TBmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1O(K(∣C∣+∣Esc∣))O(K(\lvert\mathcal{C}\rvert + \lvert\mathcal{E}_{\text{sc}}\rvert))O(K(∣C∣+∣Esc​∣))no
ULTRA-McRAPTORmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K, ext.1-to-1 / 1-to-nnnO(Kγd(N+∣T∣+∣Esc∣))O(K\gamma d(N + \lvert\mathcal{T}\rvert + \lvert E_{\text{sc}}\rvert))O(Kγd(N+∣T∣+∣Esc​∣))no
UBM-RAPTORmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K, ext., bnd.1-to-1O(KγRd(N+∣T∣+∣Esc∣))O(K\gamma_R d(N + \lvert\mathcal{T}\rvert + \lvert E_{\text{sc}}\rvert))O(KγR​d(N+∣T∣+∣Esc​∣))no
Delay-ULTRA-TBmultimodalτarr,K\tau_{\text{arr}}, Kτarr​,K1-to-1O(K(∣C∣+∣Esc∣))O(K(\lvert\mathcal{C}\rvert + \lvert\mathcal{E}_{\text{sc}}\rvert))O(K(∣C∣+∣Esc​∣))partial

"Query type" is 1-to-1, 1-to-nnn, or both; "Stable" is validity under timetable changes. Fibonacci-heap variants reduce (∣E∣+∣V∣)log⁡∣V∣(|E|+|V|)\log|V|(∣E∣+∣V∣)log∣V∣ terms to ∣E∣+∣V∣log⁡∣V∣|E|+|V|\log|V|∣E∣+∣V∣log∣V∣. N:=∑r∈R∣stops(r)∣N := \sum_{r\in\mathcal{R}}|\text{stops}(r)|N:=∑r∈R​∣stops(r)∣; "ext." = extra criteria, "bnd." = bounded variant.

References

  1. Dijkstra, Edsger W.. A Note on Two Problems in Connexion with Graphs. Numerische Mathematik, 1959.
  2. Fredman, Michael L., Tarjan, Robert Endre. Fibonacci heaps and their uses in improved network optimization algorithms. J. ACM, 1987.
  3. Hart, Peter E., Nilsson, Nils J., Raphael, Bertram. A Formal Basis for the Heuristic Determination of Minimum Cost Paths. IEEE Transactions on Systems Science and Cybernetics, 1968.
  4. Goldberg, Andrew V., Werneck, Renato F.. Computing Point-to-Point Shortest Paths from External Memory. Proceedings of the 7th Workshop on Algorithm Engineering and Experiments (ALENEX'05).
  5. Sanders, Peter, Schultes, Dominik. Highway Hierarchies Hasten Exact Shortest Path Queries. Algorithms – ESA 2005.
  6. Geisberger, Robert, Sanders, Peter, Schultes, Dominik, Vetter, Christian. Exact Routing in Large Road Networks Using Contraction Hierarchies. Transportation Science, 2012.
  7. Geisberger, Robert, Sanders, Peter, Schultes, Dominik, Delling, Daniel. Contraction Hierarchies: Faster and Simpler Hierarchical Routing in Road Networks. Experimental Algorithms, 2008.
  8. Knopp, Sebastian, Sanders, Peter, Schultes, Dominik, Schulz, Frank, Wagner, Dorothea. Computing Many-to-Many Shortest Paths Using Highway Hierarchies. Proceedings of the 9th Workshop on Algorithm Engineering and Experiments (ALENEX'07), 2007.
  9. Abraham, Ittai, Delling, Daniel, Goldberg, Andrew V., Werneck, Renato F.. A Hub-Based Labeling Algorithm for Shortest Paths in Road Networks. Experimental Algorithms (SEA 2011).
  10. Bast, Hannah, Delling, Daniel, Goldberg, Andrew, Müller-Hannemann, Matthias, Pajor, Thomas, Sanders, Peter, Wagner, Dorothea, Werneck, Renato F.. Route Planning in Transportation Networks. Algorithm Engineering: Selected Results and Surveys, 2016.
  11. Bast, Hannah. Car or Public Transport—Two Worlds. Efficient Algorithms: Essays Dedicated to Kurt Mehlhorn on the Occasion of His 60th Birthday, 2009.
  12. Batz, Gernot Veit, Geisberger, Robert, Sanders, Peter, Vetter, Christian. Minimum Time-Dependent Travel Times with Contraction Hierarchies. ACM Journal of Experimental Algorithmics, 2013.
  13. Evangelia Pyrga, Frank Schulz, Dorothea Wagner, Christos Zaroliagis. Efficient Models for Timetable Information in Public Transportation Systems. ACM Journal of Experimental Algorithmics, 2008.
  14. Gerth Stølting Brodal, Riko Jacob. Time-dependent networks as models to achieve fast exact time-table queries. Electronic Notes in Theoretical Computer Science, 2003.
  15. Tung, Chi Tung, Chew, Kim Lin. A multicriteria Pareto-optimal path algorithm. European Journal of Operational Research, 1992.
  16. Daniel Delling, Thomas Pajor, Renato F. Werneck. Round-Based Public Transit Routing. Proceedings of the 14th Meeting on Algorithm Engineering and Experiments (ALENEX), 2012.
  17. Delling, Daniel, Dibbelt, Julian, Pajor, Thomas. Fast and Exact Public Transit Routing with Restricted Pareto Sets. Proceedings of the 21st Workshop on Algorithm Engineering and Experiments (ALENEX'19), 2019.
  18. Julian Dibbelt, Thomas Pajor, Ben Strasser, Dorothea Wagner. Connection Scan Algorithm. ACM Journal of Experimental Algorithmics, 2018.
  19. Sascha Witt. Trip-Based Public Transit Routing. Algorithms — ESA 2015, 2015.
  20. Agarwal, Prateek, Rambha, Tarun. Scalable Algorithms for Bicriterion Trip-Based Transit Routing. IEEE Transactions on Intelligent Transportation Systems, 2024.
  21. Witt, Sascha. Trip-Based Public Transit Routing Using Condensed Search Trees. 16th Workshop on Algorithmic Approaches for Transportation Modelling, Optimization, and Systems (ATMOS 2016), 2016.
  22. H. Bast, E. Carlsson, A. Eigenwillig, R. Geisberger, C. Harrelson, V. Raychev, F. Viger. Fast Routing in Very Large Public Transportation Networks Using Transfer Patterns. ESA 2010, 2010.
  23. Bast, Hannah, Hertel, Matthias, Storandt, Sabine. Scalable Transfer Patterns. Proceedings of the Eighteenth Workshop on Algorithm Engineering and Experiments (ALENEX), 2016.
  24. Bast, Hannah, Storandt, Sabine. Frequency-Based Search for Public Transit. Proceedings of the 22nd ACM SIGSPATIAL International Conference on Advances in Geographic Information Systems.
  25. Wagner, Dorothea, Zündorf, Tobias. Public Transit Routing with Unrestricted Walking. 17th Workshop on Algorithmic Approaches for Transportation Modelling, Optimization, and Systems (ATMOS 2017), 2017.
  26. Dibbelt, Julian, Pajor, Thomas, Wagner, Dorothea. User-Constrained Multi-Modal Route Planning. Proceedings of the 14th Workshop on Algorithm Engineering and Experiments (ALENEX).
  27. Delling, Daniel, Dibbelt, Julian, Pajor, Thomas, Wagner, Dorothea, Werneck, Renato F.. Computing Multimodal Journeys in Practice. Proceedings of the 12th International Symposium on Experimental Algorithms (SEA'13), 2013.
  28. Duc-Minh Phan, Laurent Viennot. Fast Public Transit Routing with Unrestricted Walking Through Hub Labeling. Analysis of Experimental Algorithms – Special Event, SEA² 2019, 2019.
  29. Baum, Moritz, Buchhold, Valentin, Sauer, Jonas, Wagner, Dorothea, Zündorf, Tobias. UnLimited TRAnsfers for Multi-Modal Route Planning: An Efficient Solution. Proceedings of the 27th Annual European Symposium on Algorithms (ESA'19), 2019.
  30. Moritz Potthoff, Jonas Sauer. Fast Multimodal Journey Planning for Three Criteria. 2022 Proceedings of the Symposium on Algorithm Engineering and Experiments (ALENEX), 2002.
  31. Sauer, Jonas, Wagner, Dorothea, Zündorf, Tobias. Integrating ULTRA and Trip-Based Routing. 20th Symposium on Algorithmic Approaches for Transportation Modelling, Optimization, and Systems (ATMOS 2020), 2020.
  32. Bez, Dominik. UnLimited TRAnsfer Shortcuts with Delay Tolerance for Multi-Modal Journey Planning. Karlsruhe Institute of Technology, 2020.
  33. Bez, Dominik, Sauer, Jonas. Fast and Delay-Robust Multimodal Journey Planning. Proceedings of the 26th Workshop on Algorithm Engineering and Experiments (ALENEX'24), 2024.
  34. Sauer, Jonas. Closing the Performance Gap Between Multimodal and Public Transit Journey Planning. Karlsruhe Institute of Technology (KIT), 2024.

Work with us