minotor 11.1.2 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cspell.json +7 -1
- package/CHANGELOG.md +3 -3
- package/README.md +111 -86
- package/dist/cli/perf.d.ts +57 -18
- package/dist/cli.mjs +1371 -342
- package/dist/cli.mjs.map +1 -1
- package/dist/parser.cjs.js +57 -4
- package/dist/parser.cjs.js.map +1 -1
- package/dist/parser.esm.js +57 -4
- package/dist/parser.esm.js.map +1 -1
- package/dist/router.cjs.js +1 -1
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +5 -5
- package/dist/router.esm.js +1 -1
- package/dist/router.esm.js.map +1 -1
- package/dist/router.umd.js +1 -1
- package/dist/router.umd.js.map +1 -1
- package/dist/routing/__tests__/access.test.d.ts +1 -0
- package/dist/routing/__tests__/plainRouter.test.d.ts +1 -0
- package/dist/routing/__tests__/rangeResult.test.d.ts +1 -0
- package/dist/routing/__tests__/rangeRouter.test.d.ts +1 -0
- package/dist/routing/__tests__/rangeState.test.d.ts +1 -0
- package/dist/routing/__tests__/raptor.test.d.ts +1 -0
- package/dist/routing/__tests__/state.test.d.ts +1 -0
- package/dist/routing/access.d.ts +55 -0
- package/dist/routing/plainRouter.d.ts +21 -0
- package/dist/routing/plotter.d.ts +9 -0
- package/dist/routing/query.d.ts +132 -13
- package/dist/routing/rangeResult.d.ts +155 -0
- package/dist/routing/rangeRouter.d.ts +24 -0
- package/dist/routing/rangeState.d.ts +83 -0
- package/dist/routing/raptor.d.ts +96 -0
- package/dist/routing/result.d.ts +27 -7
- package/dist/routing/route.d.ts +5 -21
- package/dist/routing/router.d.ts +20 -91
- package/dist/routing/state.d.ts +92 -17
- package/dist/timetable/route.d.ts +8 -0
- package/dist/timetable/timetable.d.ts +17 -1
- package/package.json +1 -1
- package/src/__e2e__/benchmark.json +18 -0
- package/src/__e2e__/router.test.ts +461 -127
- package/src/cli/minotor.ts +39 -3
- package/src/cli/perf.ts +324 -60
- package/src/cli/repl.ts +96 -41
- package/src/router.ts +11 -3
- package/src/routing/__tests__/access.test.ts +294 -0
- package/src/routing/__tests__/plainRouter.test.ts +1633 -0
- package/src/routing/__tests__/plotter.test.ts +8 -8
- package/src/routing/__tests__/rangeResult.test.ts +273 -0
- package/src/routing/__tests__/rangeRouter.test.ts +472 -0
- package/src/routing/__tests__/rangeState.test.ts +246 -0
- package/src/routing/__tests__/raptor.test.ts +366 -0
- package/src/routing/__tests__/result.test.ts +27 -27
- package/src/routing/__tests__/route.test.ts +28 -0
- package/src/routing/__tests__/router.test.ts +75 -1587
- package/src/routing/__tests__/state.test.ts +78 -0
- package/src/routing/access.ts +144 -0
- package/src/routing/plainRouter.ts +60 -0
- package/src/routing/plotter.ts +53 -6
- package/src/routing/query.ts +116 -13
- package/src/routing/rangeResult.ts +292 -0
- package/src/routing/rangeRouter.ts +167 -0
- package/src/routing/rangeState.ts +150 -0
- package/src/routing/raptor.ts +416 -0
- package/src/routing/result.ts +68 -26
- package/src/routing/route.ts +15 -53
- package/src/routing/router.ts +40 -480
- package/src/routing/state.ts +191 -32
- package/src/timetable/__tests__/timetable.test.ts +373 -0
- package/src/timetable/route.ts +16 -4
- package/src/timetable/timetable.ts +54 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { StopId } from '../stops/stops.js';
|
|
2
|
+
import { StopsIndex } from '../stops/stopsIndex.js';
|
|
3
|
+
import { Duration, Time } from '../timetable/time.js';
|
|
4
|
+
import { Timetable } from '../timetable/timetable.js';
|
|
5
|
+
/**
|
|
6
|
+
* An access path from the query origin to an initial boarding stop.
|
|
7
|
+
*
|
|
8
|
+
* Equivalent origin stops (reached at zero cost) have no `duration`.
|
|
9
|
+
* Stops reachable via a timed walking transfer carry a `duration` in minutes.
|
|
10
|
+
*/
|
|
11
|
+
export type AccessPoint = {
|
|
12
|
+
fromStopId: StopId;
|
|
13
|
+
toStopId: StopId;
|
|
14
|
+
duration: Duration;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Collects access paths from a query origin and resolves the set of
|
|
18
|
+
* distinct departure-time slots for Range RAPTOR.
|
|
19
|
+
*/
|
|
20
|
+
export declare class AccessFinder {
|
|
21
|
+
private readonly timetable;
|
|
22
|
+
private readonly stopsIndex;
|
|
23
|
+
constructor(timetable: Timetable, stopsIndex: StopsIndex);
|
|
24
|
+
/**
|
|
25
|
+
* Returns every initial access path from the query origin: equivalent stops
|
|
26
|
+
* (no duration) plus every stop reachable via a single timed walking transfer
|
|
27
|
+
* (REQUIRES_MINIMAL_TIME), keeping the shortest walk when multiple origins
|
|
28
|
+
* can reach the same stop.
|
|
29
|
+
*
|
|
30
|
+
* @param origin Origin stop ID.
|
|
31
|
+
* @param fallbackMinTransferTime Transfer time used when a walking transfer
|
|
32
|
+
* has no explicit `minTransferTime` in the timetable data.
|
|
33
|
+
*/
|
|
34
|
+
collectAccessPaths(queryOrigin: StopId, fallbackMinTransferTime: Duration): AccessPoint[];
|
|
35
|
+
/**
|
|
36
|
+
* Collects all distinct origin departure times within `[from, to]`
|
|
37
|
+
* (inclusive) and, for each slot, the specific access paths that directly
|
|
38
|
+
* induce it — i.e. paths whose boarded stop has a boardable trip departing
|
|
39
|
+
* at exactly `depTime + path.duration`.
|
|
40
|
+
*
|
|
41
|
+
* Returned array is sorted **latest-first**. The Range RAPTOR outer loop
|
|
42
|
+
* seeds only the responsible paths for each slot, avoiding redundant
|
|
43
|
+
* exploration of access stops whose boarding opportunities belong to a
|
|
44
|
+
* later slot and whose journeys would therefore be dominated by it.
|
|
45
|
+
*
|
|
46
|
+
|
|
47
|
+
* @param accessPaths Access paths from the origin to initial boarding stops.
|
|
48
|
+
* @param from Earliest origin departure time (inclusive).
|
|
49
|
+
* @param to Latest origin departure time (inclusive).
|
|
50
|
+
*/
|
|
51
|
+
collectDepartureTimes(accessPaths: AccessPoint[], from: Time, to: Time): {
|
|
52
|
+
depTime: Time;
|
|
53
|
+
legs: AccessPoint[];
|
|
54
|
+
}[];
|
|
55
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { StopsIndex } from '../stops/stopsIndex.js';
|
|
2
|
+
import { Timetable } from '../timetable/timetable.js';
|
|
3
|
+
import { AccessFinder } from './access.js';
|
|
4
|
+
import { Query } from './query.js';
|
|
5
|
+
import { Raptor } from './raptor.js';
|
|
6
|
+
import { Result } from './result.js';
|
|
7
|
+
export declare class PlainRouter {
|
|
8
|
+
private readonly timetable;
|
|
9
|
+
private readonly stopsIndex;
|
|
10
|
+
private readonly accessFinder;
|
|
11
|
+
private readonly raptor;
|
|
12
|
+
constructor(timetable: Timetable, stopsIndex: StopsIndex, accessFinder: AccessFinder, raptor: Raptor);
|
|
13
|
+
/**
|
|
14
|
+
* Standard RAPTOR: finds the earliest-arrival journey from `query.from` to
|
|
15
|
+
* `query.to` for the given departure time.
|
|
16
|
+
*
|
|
17
|
+
* @param query The routing query.
|
|
18
|
+
* @returns A {@link Result} that can reconstruct the best route and arrival times.
|
|
19
|
+
*/
|
|
20
|
+
route(query: Query): Result;
|
|
21
|
+
}
|
|
@@ -30,6 +30,10 @@ export declare class Plotter {
|
|
|
30
30
|
* Generates a unique node ID for a transfer edge oval.
|
|
31
31
|
*/
|
|
32
32
|
private transferEdgeNodeId;
|
|
33
|
+
/**
|
|
34
|
+
* Generates a unique node ID for a walking access edge oval.
|
|
35
|
+
*/
|
|
36
|
+
private accessEdgeNodeId;
|
|
33
37
|
/**
|
|
34
38
|
* Generates a unique node ID for a continuation edge oval.
|
|
35
39
|
*/
|
|
@@ -70,6 +74,11 @@ export declare class Plotter {
|
|
|
70
74
|
* Creates a vehicle edge with route information oval in the middle.
|
|
71
75
|
*/
|
|
72
76
|
private createVehicleEdge;
|
|
77
|
+
/**
|
|
78
|
+
* Creates a walking access leg as a dashed oval connecting the query origin
|
|
79
|
+
* to the initial boarding stop.
|
|
80
|
+
*/
|
|
81
|
+
private createAccessEdge;
|
|
73
82
|
/**
|
|
74
83
|
* Creates a transfer edge with transfer information oval in the middle.
|
|
75
84
|
*/
|
package/dist/routing/query.d.ts
CHANGED
|
@@ -5,12 +5,27 @@ export type QueryOptions = {
|
|
|
5
5
|
maxTransfers: number;
|
|
6
6
|
minTransferTime: Duration;
|
|
7
7
|
transportModes: Set<RouteType>;
|
|
8
|
+
/**
|
|
9
|
+
* Maximum time (in minutes) the traveler is willing to wait at the first
|
|
10
|
+
* boarding stop before the first transit vehicle departs.
|
|
11
|
+
*
|
|
12
|
+
* When set, any trip that would require waiting longer than this duration
|
|
13
|
+
* after arriving at the stop is skipped for the first boarding leg.
|
|
14
|
+
* Undefined means no limit.
|
|
15
|
+
*/
|
|
16
|
+
maxInitialWaitingTime?: Duration;
|
|
8
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* A routing query for standard RAPTOR.
|
|
20
|
+
*
|
|
21
|
+
* Finds the earliest-arrival journey from `from` to `to` for a single
|
|
22
|
+
* departure time. Use {@link RangeQuery} (and `router.rangeRoute()`) when
|
|
23
|
+
* you want all Pareto-optimal journeys within a departure-time window.
|
|
24
|
+
*/
|
|
9
25
|
export declare class Query {
|
|
10
26
|
from: StopId;
|
|
11
27
|
to: Set<StopId>;
|
|
12
28
|
departureTime: Time;
|
|
13
|
-
lastDepartureTime?: Time;
|
|
14
29
|
options: QueryOptions;
|
|
15
30
|
constructor(builder: typeof Query.Builder.prototype);
|
|
16
31
|
static Builder: {
|
|
@@ -18,23 +33,19 @@ export declare class Query {
|
|
|
18
33
|
fromValue: StopId;
|
|
19
34
|
toValue: Set<StopId>;
|
|
20
35
|
departureTimeValue: Time;
|
|
21
|
-
optionsValue:
|
|
22
|
-
maxTransfers: number;
|
|
23
|
-
minTransferTime: Duration;
|
|
24
|
-
transportModes: Set<RouteType>;
|
|
25
|
-
};
|
|
36
|
+
optionsValue: QueryOptions;
|
|
26
37
|
/**
|
|
27
38
|
* Sets the starting stop.
|
|
28
39
|
*/
|
|
29
40
|
from(from: StopId): /*elided*/ any;
|
|
30
41
|
/**
|
|
31
|
-
* Sets the destination
|
|
42
|
+
* Sets the destination stop(s).
|
|
43
|
+
* Routing stops as soon as all provided stops have been reached.
|
|
32
44
|
*/
|
|
33
45
|
to(to: StopId | Set<StopId>): /*elided*/ any;
|
|
34
46
|
/**
|
|
35
|
-
* Sets the departure time
|
|
36
|
-
*
|
|
37
|
-
* even if a later route might arrive at the same time.
|
|
47
|
+
* Sets the departure time in minutes from midnight.
|
|
48
|
+
* The router favours trips departing shortly after this time.
|
|
38
49
|
*/
|
|
39
50
|
departureTime(departureTime: Time): /*elided*/ any;
|
|
40
51
|
/**
|
|
@@ -42,15 +53,123 @@ export declare class Query {
|
|
|
42
53
|
*/
|
|
43
54
|
maxTransfers(maxTransfers: number): /*elided*/ any;
|
|
44
55
|
/**
|
|
45
|
-
* Sets the minimum transfer time (in minutes)
|
|
46
|
-
*
|
|
56
|
+
* Sets the fallback minimum transfer time (in minutes) used when the
|
|
57
|
+
* timetable data does not specify one for a particular transfer.
|
|
47
58
|
*/
|
|
48
59
|
minTransferTime(minTransferTime: Duration): /*elided*/ any;
|
|
49
60
|
/**
|
|
50
|
-
*
|
|
61
|
+
* Restricts routing to the given transport modes.
|
|
51
62
|
*/
|
|
52
63
|
transportModes(transportModes: Set<RouteType>): /*elided*/ any;
|
|
64
|
+
/**
|
|
65
|
+
* Sets the maximum time (in minutes) the traveler is willing to wait at
|
|
66
|
+
* the first boarding stop before the first transit vehicle departs.
|
|
67
|
+
*
|
|
68
|
+
* When set, any trip that would require waiting longer than this duration
|
|
69
|
+
* after arriving at the stop is not considered for the first boarding leg.
|
|
70
|
+
*/
|
|
71
|
+
maxInitialWaitingTime(maxInitialWaitingTime: Duration): /*elided*/ any;
|
|
53
72
|
build(): Query;
|
|
54
73
|
};
|
|
55
74
|
};
|
|
56
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Options specific to a {@link RangeQuery}.
|
|
78
|
+
*/
|
|
79
|
+
export type RangeQueryOptions = {
|
|
80
|
+
/**
|
|
81
|
+
* When `true`, a full RAPTOR pass is run at `lastDepartureTime + 1` before
|
|
82
|
+
* the main departure-time loop (the *boundary run*).
|
|
83
|
+
*
|
|
84
|
+
* The boundary run seeds the shared Pareto labels with the best arrival
|
|
85
|
+
* achievable by departing just after the window closes. Any in-window
|
|
86
|
+
* journey whose arrival is no better than what that post-window departure
|
|
87
|
+
* achieves is therefore suppressed — you only see journeys that are still
|
|
88
|
+
* worth taking given that a later departure exists.
|
|
89
|
+
*
|
|
90
|
+
* **Timetable use-case** (`boundaryRun: true`): the window is a *display
|
|
91
|
+
* filter*. A journey at 10:55 that arrives at 12:30 is hidden when an
|
|
92
|
+
* 11:05 departure arrives at 12:00 — the router pre-empts the dominated
|
|
93
|
+
* option on the caller's behalf.
|
|
94
|
+
*
|
|
95
|
+
* **Isochrone / accessibility use-case** (`boundaryRun: false`, the
|
|
96
|
+
* default): the window is a hard constraint. Every Pareto-optimal journey
|
|
97
|
+
* whose departure falls strictly within `[departureTime, lastDepartureTime]`
|
|
98
|
+
* is returned, regardless of what might be available just outside the
|
|
99
|
+
* window.
|
|
100
|
+
*
|
|
101
|
+
* @default false
|
|
102
|
+
*/
|
|
103
|
+
optimizeBeyondLatestDeparture: boolean;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* A routing query for Range RAPTOR.
|
|
107
|
+
*
|
|
108
|
+
* Extends {@link Query} with a required `lastDepartureTime` that defines the
|
|
109
|
+
* upper bound of the departure-time window. `router.rangeRoute()` returns
|
|
110
|
+
* all Pareto-optimal journeys departing in
|
|
111
|
+
* `[departureTime, lastDepartureTime]`.
|
|
112
|
+
*
|
|
113
|
+
*/
|
|
114
|
+
export declare class RangeQuery extends Query {
|
|
115
|
+
/** Upper bound of the departure-time window (minutes from midnight). */
|
|
116
|
+
readonly lastDepartureTime: Time;
|
|
117
|
+
/** Options specific to Range RAPTOR behavior. */
|
|
118
|
+
readonly rangeOptions: RangeQueryOptions;
|
|
119
|
+
constructor(builder: typeof RangeQuery.Builder.prototype);
|
|
120
|
+
static Builder: {
|
|
121
|
+
new (): {
|
|
122
|
+
lastDepartureTimeValue: Time;
|
|
123
|
+
rangeOptionsValue: RangeQueryOptions;
|
|
124
|
+
/**
|
|
125
|
+
* Sets the upper bound of the departure-time window.
|
|
126
|
+
*/
|
|
127
|
+
lastDepartureTime(time: Time): /*elided*/ any;
|
|
128
|
+
/**
|
|
129
|
+
* Overrides individual Range RAPTOR options.
|
|
130
|
+
* Unspecified fields keep their defaults.
|
|
131
|
+
*/
|
|
132
|
+
rangeOptions(options: Partial<RangeQueryOptions>): /*elided*/ any;
|
|
133
|
+
build(): RangeQuery;
|
|
134
|
+
fromValue: StopId;
|
|
135
|
+
toValue: Set<StopId>;
|
|
136
|
+
departureTimeValue: Time;
|
|
137
|
+
optionsValue: QueryOptions;
|
|
138
|
+
/**
|
|
139
|
+
* Sets the starting stop.
|
|
140
|
+
*/
|
|
141
|
+
from(from: StopId): /*elided*/ any;
|
|
142
|
+
/**
|
|
143
|
+
* Sets the destination stop(s).
|
|
144
|
+
* Routing stops as soon as all provided stops have been reached.
|
|
145
|
+
*/
|
|
146
|
+
to(to: StopId | Set<StopId>): /*elided*/ any;
|
|
147
|
+
/**
|
|
148
|
+
* Sets the departure time in minutes from midnight.
|
|
149
|
+
* The router favours trips departing shortly after this time.
|
|
150
|
+
*/
|
|
151
|
+
departureTime(departureTime: Time): /*elided*/ any;
|
|
152
|
+
/**
|
|
153
|
+
* Sets the maximum number of transfers allowed.
|
|
154
|
+
*/
|
|
155
|
+
maxTransfers(maxTransfers: number): /*elided*/ any;
|
|
156
|
+
/**
|
|
157
|
+
* Sets the fallback minimum transfer time (in minutes) used when the
|
|
158
|
+
* timetable data does not specify one for a particular transfer.
|
|
159
|
+
*/
|
|
160
|
+
minTransferTime(minTransferTime: Duration): /*elided*/ any;
|
|
161
|
+
/**
|
|
162
|
+
* Restricts routing to the given transport modes.
|
|
163
|
+
*/
|
|
164
|
+
transportModes(transportModes: Set<RouteType>): /*elided*/ any;
|
|
165
|
+
/**
|
|
166
|
+
* Sets the maximum time (in minutes) the traveler is willing to wait at
|
|
167
|
+
* the first boarding stop before the first transit vehicle departs.
|
|
168
|
+
*
|
|
169
|
+
* When set, any trip that would require waiting longer than this duration
|
|
170
|
+
* after arriving at the stop is not considered for the first boarding leg.
|
|
171
|
+
*/
|
|
172
|
+
maxInitialWaitingTime(maxInitialWaitingTime: Duration): /*elided*/ any;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { StopId } from '../stops/stops.js';
|
|
2
|
+
import { Duration, Time } from '../timetable/time.js';
|
|
3
|
+
import { Result } from './result.js';
|
|
4
|
+
import { Route } from './route.js';
|
|
5
|
+
import { Arrival } from './state.js';
|
|
6
|
+
/**
|
|
7
|
+
* A single departure-time iteration that produced at least one Pareto-optimal
|
|
8
|
+
* journey to this result's destination set.
|
|
9
|
+
*/
|
|
10
|
+
export type ParetoRun = {
|
|
11
|
+
/** Departure time from the origin (minutes from midnight) for this run. */
|
|
12
|
+
readonly departureTime: Time;
|
|
13
|
+
/** Full RAPTOR result for this departure time — use it to reconstruct routes. */
|
|
14
|
+
readonly result: Result;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* An {@link Arrival} enriched with the travel duration from the origin.
|
|
18
|
+
*
|
|
19
|
+
* Returned by duration-based methods on {@link RangeResult} so callers
|
|
20
|
+
* receive both the absolute arrival time with transfer count *and* the total
|
|
21
|
+
* travel time that was optimized over.
|
|
22
|
+
*/
|
|
23
|
+
export type ArrivalWithDuration = Arrival & {
|
|
24
|
+
/** Total travel time from origin departure to stop arrival (minutes). */
|
|
25
|
+
readonly duration: Duration;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The result of a Range RAPTOR query.
|
|
29
|
+
*
|
|
30
|
+
* Contains the complete Pareto-optimal set of journeys for a resolved
|
|
31
|
+
* destination set.
|
|
32
|
+
*
|
|
33
|
+
* **Pareto dominance**: journey J1 dominates J2 iff
|
|
34
|
+
* `τdep(J1) ≥ τdep(J2) AND τarr(J1) ≤ τarr(J2)`
|
|
35
|
+
* (with at least one strict inequality).
|
|
36
|
+
*
|
|
37
|
+
* Runs are ordered **latest-departure-first**: each successive run departs
|
|
38
|
+
* strictly earlier *and* arrives strictly earlier than the previous one,
|
|
39
|
+
* forming the classic staircase Pareto frontier.
|
|
40
|
+
*
|
|
41
|
+
* Destination handling is delegated to {@link Result}, which expands
|
|
42
|
+
* equivalent stops when reconstructing routes or looking up arrivals.
|
|
43
|
+
*/
|
|
44
|
+
export declare class RangeResult {
|
|
45
|
+
private readonly _runs;
|
|
46
|
+
private readonly _destinations;
|
|
47
|
+
constructor(runs: ParetoRun[], destinations: ReadonlySet<StopId>);
|
|
48
|
+
/** The resolved destination stop IDs for this result. */
|
|
49
|
+
get destinations(): ReadonlySet<StopId>;
|
|
50
|
+
private normalizeTargets;
|
|
51
|
+
/**
|
|
52
|
+
* Returns all non-dominated routes to this result's default destination set,
|
|
53
|
+
* ordered from the earliest departure to the latest departure.
|
|
54
|
+
*
|
|
55
|
+
* Each route in the list departs strictly earlier *and* arrives strictly
|
|
56
|
+
* earlier than its predecessor.
|
|
57
|
+
*/
|
|
58
|
+
getRoutes(): Route[];
|
|
59
|
+
/**
|
|
60
|
+
* The route that arrives **earliest** at the given stop(s) across all
|
|
61
|
+
* Pareto-optimal runs.
|
|
62
|
+
*
|
|
63
|
+
* When two runs achieve the same arrival time at the target, the one with
|
|
64
|
+
* the **later departure** is preferred — you wait at the origin rather than
|
|
65
|
+
* at a transit stop.
|
|
66
|
+
*
|
|
67
|
+
* Defaults to this result's own destination stop(s) when `to` is omitted.
|
|
68
|
+
*
|
|
69
|
+
* @param to Optional destination stop ID or set of stop IDs.
|
|
70
|
+
* @returns The reconstructed {@link Route} with the earliest arrival,
|
|
71
|
+
* or `undefined` if the target is unreachable in every run.
|
|
72
|
+
*/
|
|
73
|
+
bestRoute(to?: StopId | Set<StopId>): Route | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* The route with the **latest possible departure** from the origin among all
|
|
76
|
+
* Pareto-optimal journeys in the window.
|
|
77
|
+
*
|
|
78
|
+
* This is the journey that lets you leave the origin as late as possible.
|
|
79
|
+
* It does **not** necessarily achieve the earliest arrival — for that, use
|
|
80
|
+
* {@link bestRoute}. For the shortest travel duration, use
|
|
81
|
+
* {@link fastestRoute}.
|
|
82
|
+
*
|
|
83
|
+
* Defaults to this result's own destination stop(s) when `to` is omitted.
|
|
84
|
+
*
|
|
85
|
+
* @param to Optional destination stop ID or set of stop IDs.
|
|
86
|
+
* @returns The reconstructed {@link Route} with the latest departure,
|
|
87
|
+
* or `undefined` if the target is unreachable in every run.
|
|
88
|
+
*/
|
|
89
|
+
latestDepartureRoute(to?: StopId | Set<StopId>): Route | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Reconstructs the **fastest** route to the given stop(s) — the journey with
|
|
92
|
+
* the shortest travel duration (arrival time − origin departure time) across
|
|
93
|
+
* all Pareto-optimal runs.
|
|
94
|
+
*
|
|
95
|
+
* Unlike {@link bestRoute}, which returns the route that departs as late as
|
|
96
|
+
* possible while still arriving early, this method minimizes total time
|
|
97
|
+
* spent traveling.
|
|
98
|
+
*
|
|
99
|
+
* Defaults to this result's own destination stop(s) when `to` is omitted.
|
|
100
|
+
*
|
|
101
|
+
* @param to Optional destination stop ID or set of stop IDs.
|
|
102
|
+
* @returns The reconstructed fastest {@link Route}, or `undefined` if the
|
|
103
|
+
* target is unreachable in every run.
|
|
104
|
+
*/
|
|
105
|
+
fastestRoute(to?: StopId | Set<StopId>): Route | undefined;
|
|
106
|
+
/** Number of Pareto-optimal journeys found. */
|
|
107
|
+
get size(): number;
|
|
108
|
+
/**
|
|
109
|
+
* Earliest achievable arrival at a stop across all Pareto-optimal runs.
|
|
110
|
+
*
|
|
111
|
+
* Useful for isochrone / accessibility analysis: given this result's
|
|
112
|
+
* departure-time frontier, how early can you reach stop `s` regardless of
|
|
113
|
+
* which specific trip you take?
|
|
114
|
+
*
|
|
115
|
+
* Equivalent stops are handled by {@link Result.arrivalAt}.
|
|
116
|
+
*
|
|
117
|
+
* @param stop The target stop ID.
|
|
118
|
+
* @param maxTransfers Optional upper bound on the number of transfers.
|
|
119
|
+
*/
|
|
120
|
+
earliestArrivalAt(stop: StopId, maxTransfers?: number): Arrival | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* Shortest travel duration to reach a stop across all Pareto-optimal runs.
|
|
123
|
+
*
|
|
124
|
+
* For each run, duration is measured from the run's origin departure time to
|
|
125
|
+
* the earliest arrival at `stop` within that run. The minimum across all
|
|
126
|
+
* runs is returned.
|
|
127
|
+
*
|
|
128
|
+
* Equivalent stops are handled by {@link Result.arrivalAt}.
|
|
129
|
+
*
|
|
130
|
+
* Duration is **not** monotone along the Pareto frontier — a run that
|
|
131
|
+
* departs later may still travel faster — so every run is checked. In
|
|
132
|
+
* practice the Pareto frontier is small, so this is O(runs).
|
|
133
|
+
*
|
|
134
|
+
* Returns `undefined` if `stop` is unreachable in every run.
|
|
135
|
+
*
|
|
136
|
+
* @param stop The target stop ID.
|
|
137
|
+
* @param maxTransfers Optional upper bound on the number of transfers.
|
|
138
|
+
*/
|
|
139
|
+
shortestDurationTo(stop: StopId, maxTransfers?: number): ArrivalWithDuration | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* Shortest travel duration to **every reachable stop** across all
|
|
142
|
+
* Pareto-optimal runs, as a single `Map<StopId, DurationArrival>`.
|
|
143
|
+
*/
|
|
144
|
+
allShortestDurations(): Map<StopId, ArrivalWithDuration>;
|
|
145
|
+
/**
|
|
146
|
+
* Earliest achievable arrival at **every reachable stop** across all
|
|
147
|
+
* Pareto-optimal runs, as a single `Map<StopId, Arrival>`.
|
|
148
|
+
*/
|
|
149
|
+
allEarliestArrivals(): Map<StopId, Arrival>;
|
|
150
|
+
/**
|
|
151
|
+
* Iterates over all Pareto-optimal `(departureTime, result)` pairs,
|
|
152
|
+
* ordered from the latest departure to the earliest departure.
|
|
153
|
+
*/
|
|
154
|
+
[Symbol.iterator](): IterableIterator<ParetoRun>;
|
|
155
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { StopsIndex } from '../stops/stopsIndex.js';
|
|
2
|
+
import { Timetable } from '../timetable/timetable.js';
|
|
3
|
+
import { AccessFinder } from './access.js';
|
|
4
|
+
import { RangeQuery } from './query.js';
|
|
5
|
+
import { RangeResult } from './rangeResult.js';
|
|
6
|
+
import { Raptor } from './raptor.js';
|
|
7
|
+
export declare class RangeRouter {
|
|
8
|
+
private readonly timetable;
|
|
9
|
+
private readonly stopsIndex;
|
|
10
|
+
private readonly accessFinder;
|
|
11
|
+
private readonly raptor;
|
|
12
|
+
constructor(timetable: Timetable, stopsIndex: StopsIndex, accessFinder: AccessFinder, raptor: Raptor);
|
|
13
|
+
/**
|
|
14
|
+
* Range RAPTOR: finds all Pareto-optimal journeys within the departure-time
|
|
15
|
+
* window `[query.departureTime, query.lastDepartureTime]`.
|
|
16
|
+
*
|
|
17
|
+
* A journey is Pareto-optimal iff no journey departing no earlier arrives no
|
|
18
|
+
* later. Runs are ordered latest-departure-first in the returned result.
|
|
19
|
+
*
|
|
20
|
+
* @param query A {@link RangeQuery} with both `departureTime` and `lastDepartureTime` set.
|
|
21
|
+
* @returns A {@link RangeResult} exposing the full Pareto frontier.
|
|
22
|
+
*/
|
|
23
|
+
rangeRoute(query: RangeQuery): RangeResult;
|
|
24
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { StopId } from '../stops/stops.js';
|
|
2
|
+
import { Time } from '../timetable/time.js';
|
|
3
|
+
import type { IRaptorState } from './raptor.js';
|
|
4
|
+
import { RoutingEdge, RoutingState } from './state.js';
|
|
5
|
+
/**
|
|
6
|
+
* RAPTOR state for Range RAPTOR mode, implementing {@link IRaptorState}.
|
|
7
|
+
*
|
|
8
|
+
* Holds both the cross-run shared labels (carried over from one departure-time
|
|
9
|
+
* iteration to the next, latest → earliest) and a reference to the current
|
|
10
|
+
* per-iteration {@link RoutingState} (swapped via {@link setCurrentRun}).
|
|
11
|
+
*
|
|
12
|
+
* Concretely, `roundLabels[k][p]` is the best known arrival at stop `p` using
|
|
13
|
+
* at most `k` transit legs, across **all departure times tried so far**.
|
|
14
|
+
*
|
|
15
|
+
* @see https://www.microsoft.com/en-us/research/wp-content/uploads/2012/01/raptor_alenex.pdf
|
|
16
|
+
*/
|
|
17
|
+
export declare class RangeRaptorState implements IRaptorState {
|
|
18
|
+
/**
|
|
19
|
+
* `roundLabels[k]` is a flat `Uint16Array` of size `nbStops`.
|
|
20
|
+
* `roundLabels[k][p]` = best arrival time (minutes from midnight) at stop `p`
|
|
21
|
+
* in round `k`, across all departure-time iterations processed so far.
|
|
22
|
+
* Pre-filled with `UNREACHED_TIME`; updated in-place as better arrivals are found.
|
|
23
|
+
*/
|
|
24
|
+
readonly roundLabels: Uint16Array[];
|
|
25
|
+
/**
|
|
26
|
+
* The latest departure time of the range query.
|
|
27
|
+
*/
|
|
28
|
+
readonly latestDeparture: Time;
|
|
29
|
+
/**
|
|
30
|
+
* Global best arrival at any destination stop across all runs and rounds.
|
|
31
|
+
* Used for destination-pruning inside scan methods so that routes that cannot
|
|
32
|
+
* beat the already-known best are skipped early.
|
|
33
|
+
*/
|
|
34
|
+
private _destinationBest;
|
|
35
|
+
/**
|
|
36
|
+
* Sparse change-tracking for `initRound`.
|
|
37
|
+
*
|
|
38
|
+
* `changedInRound[k]` is the list of stops whose round-k label was improved
|
|
39
|
+
* (via `tryImprove`) since the last call to `initRound(k + 1)`. When
|
|
40
|
+
* `initRound(k + 1)` runs, it only visits these stops instead of scanning
|
|
41
|
+
* all `nbStops` entries, reducing the work from O(nbStops × rounds ×
|
|
42
|
+
* departureTimes) to O(changedStops × rounds × departureTimes).
|
|
43
|
+
*
|
|
44
|
+
* Duplicates are allowed and harmless — a stop that appears twice merely
|
|
45
|
+
* receives a redundant (no-op) min-update on the second visit. The list is
|
|
46
|
+
* cleared inside `initRound` immediately after processing.
|
|
47
|
+
*/
|
|
48
|
+
private readonly changedInRound;
|
|
49
|
+
private currentRun;
|
|
50
|
+
constructor(maxRounds: number, nbStops: number, latestDeparture: Time);
|
|
51
|
+
/**
|
|
52
|
+
* Swaps in a fresh {@link RoutingState} for the next departure-time iteration
|
|
53
|
+
* and seeds the shared round-0 labels from its access arrivals.
|
|
54
|
+
*
|
|
55
|
+
* Must be called before every `runRaptor` invocation.
|
|
56
|
+
*/
|
|
57
|
+
setCurrentRun(routingState: RoutingState): void;
|
|
58
|
+
get origins(): StopId[];
|
|
59
|
+
get graph(): (RoutingEdge | undefined)[][];
|
|
60
|
+
arrivalTime(stop: StopId): Time;
|
|
61
|
+
/**
|
|
62
|
+
* Uses the cross-run shared label for `round`, which is always at least as
|
|
63
|
+
* tight as the per-run arrival and therefore provides stronger pruning.
|
|
64
|
+
*/
|
|
65
|
+
improvementBound(round: number, stop: StopId): Time;
|
|
66
|
+
/**
|
|
67
|
+
* Global best arrival at any destination across all departure-time iterations.
|
|
68
|
+
* Always at least as tight as the per-run `destinationBest`.
|
|
69
|
+
*/
|
|
70
|
+
get destinationBest(): Time;
|
|
71
|
+
isDestination(stop: StopId): boolean;
|
|
72
|
+
/** Updates both the per-run state and the cross-run shared labels. */
|
|
73
|
+
updateArrival(stop: StopId, time: Time, round: number): void;
|
|
74
|
+
/**
|
|
75
|
+
* initialized round `k` from round `k-1`: τk(p) ← min(τk(p), τk-1(p)).
|
|
76
|
+
*
|
|
77
|
+
* Must be called at the very start of each RAPTOR round before routes are
|
|
78
|
+
* scanned. After this call, `roundLabels[k][p]` is the minimum arrival at
|
|
79
|
+
* stop `p` achievable with **at most** k transit legs from any departure time
|
|
80
|
+
* tried so far — which is exactly the tightest valid pruning bound for round k.
|
|
81
|
+
*/
|
|
82
|
+
initRound(round: number): void;
|
|
83
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { StopId } from '../stops/stops.js';
|
|
2
|
+
import { Time } from '../timetable/time.js';
|
|
3
|
+
import { Timetable } from '../timetable/timetable.js';
|
|
4
|
+
import { QueryOptions } from './query.js';
|
|
5
|
+
import { RoutingEdge } from './state.js';
|
|
6
|
+
/**
|
|
7
|
+
* Common interface for all variants of RAPTOR routing.
|
|
8
|
+
*/
|
|
9
|
+
export interface IRaptorState {
|
|
10
|
+
/** Origin stop IDs for this run. */
|
|
11
|
+
readonly origins: StopId[];
|
|
12
|
+
/** Per-round routing graph; `graph[round][stop]` is the best edge used to reach `stop`. */
|
|
13
|
+
readonly graph: (RoutingEdge | undefined)[][];
|
|
14
|
+
/** Per-run earliest arrival at a stop. Used for boarding decisions. */
|
|
15
|
+
arrivalTime(stop: StopId): Time;
|
|
16
|
+
/**
|
|
17
|
+
* Tightest known upper bound on the arrival time at `stop` in `round`.
|
|
18
|
+
*/
|
|
19
|
+
improvementBound(round: number, stop: StopId): Time;
|
|
20
|
+
/**
|
|
21
|
+
* Best known arrival time at any destination.
|
|
22
|
+
*/
|
|
23
|
+
readonly destinationBest: Time;
|
|
24
|
+
/** Returns `true` if `stop` is one of the query's destination stops. */
|
|
25
|
+
isDestination(stop: StopId): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Records a new arrival at `stop`, updating all relevant state.
|
|
28
|
+
*
|
|
29
|
+
* In Range RAPTOR mode this also updates the cross-run shared labels.
|
|
30
|
+
*/
|
|
31
|
+
updateArrival(stop: StopId, time: Time, round: number): void;
|
|
32
|
+
/**
|
|
33
|
+
* Propagates labels from round `k-1` into round `k` before routes are scanned.
|
|
34
|
+
* No-op in standard RAPTOR mode.
|
|
35
|
+
*/
|
|
36
|
+
initRound(round: number): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Encapsulates the core RAPTOR algorithm, operating on a {@link Timetable} and
|
|
40
|
+
* an {@link IRaptorState} provided by the caller.
|
|
41
|
+
*
|
|
42
|
+
* @see https://www.microsoft.com/en-us/research/wp-content/uploads/2012/01/raptor_alenex.pdf
|
|
43
|
+
*/
|
|
44
|
+
export declare class Raptor {
|
|
45
|
+
private readonly timetable;
|
|
46
|
+
constructor(timetable: Timetable);
|
|
47
|
+
run(options: QueryOptions, state: IRaptorState): void;
|
|
48
|
+
/**
|
|
49
|
+
* Finds trip continuations for the given marked stops and edges at the current round.
|
|
50
|
+
* @param markedStops The set of marked stops.
|
|
51
|
+
* @param edgesAtCurrentRound The array of edges at the current round, indexed by stop ID.
|
|
52
|
+
* @returns An array of trip continuations.
|
|
53
|
+
*/
|
|
54
|
+
private findTripContinuations;
|
|
55
|
+
/**
|
|
56
|
+
* Scans a route for an in-seat trip continuation.
|
|
57
|
+
*
|
|
58
|
+
* The boarded trip and entry stop are fixed, so there is no need to probe for
|
|
59
|
+
* earlier boardings.
|
|
60
|
+
*
|
|
61
|
+
* @param route The route to scan
|
|
62
|
+
* @param hopOnStopIndex The stop index where the continuation begins
|
|
63
|
+
* @param round The current RAPTOR round
|
|
64
|
+
* @param routingState Current routing state
|
|
65
|
+
* @param tripContinuation The in-seat continuation descriptor
|
|
66
|
+
* @param shared Optional shared state for Range RAPTOR mode
|
|
67
|
+
*/
|
|
68
|
+
private scanRouteContinuation;
|
|
69
|
+
/**
|
|
70
|
+
* Scans a route using the standard RAPTOR boarding logic.
|
|
71
|
+
*
|
|
72
|
+
* Iterates through all stops from the hop-on point, maintaining the current
|
|
73
|
+
* best trip and improving arrival times when possible. At each marked stop it
|
|
74
|
+
* also checks whether an earlier (or first) trip can be boarded, upgrading the
|
|
75
|
+
* active trip when one is found.
|
|
76
|
+
*
|
|
77
|
+
* @param route The route to scan
|
|
78
|
+
* @param hopOnStopIndex The stop index where passengers can first board
|
|
79
|
+
* @param round The current RAPTOR round
|
|
80
|
+
* @param state Current routing state
|
|
81
|
+
* @param options Query options (minTransferTime, etc.)
|
|
82
|
+
*/
|
|
83
|
+
private scanRoute;
|
|
84
|
+
/**
|
|
85
|
+
* Processes all currently marked stops to find available transfers
|
|
86
|
+
* and determines if using these transfers would result in earlier arrival times
|
|
87
|
+
* at destination stops. It handles different transfer types including in-seat
|
|
88
|
+
* transfers and walking transfers with appropriate minimum transfer times.
|
|
89
|
+
*
|
|
90
|
+
* @param options Query options (minTransferTime, etc.)
|
|
91
|
+
* @param round The current round number in the RAPTOR algorithm
|
|
92
|
+
* @param markedStops The set of currently marked stops
|
|
93
|
+
* @param state Current routing state
|
|
94
|
+
*/
|
|
95
|
+
private considerTransfers;
|
|
96
|
+
}
|