minotor
Version:
A lightweight client-side transit routing library.
205 lines (204 loc) • 8.27 kB
TypeScript
import { StopId } from '../stops/stops.js';
import { StopRouteIndex } from '../timetable/route.js';
import { Duration, Time } from '../timetable/time.js';
import { TransferType, TripStop } from '../timetable/timetable.js';
import { AccessPoint } from './access.js';
import type { IRaptorState } from './raptor.js';
/**
* Sentinel value used in the internal arrival-time array to mark stops not yet reached.
* 0xFFFF = 65 535 minutes ≈ 45.5 days, safely beyond any realistic transit arrival time.
*/
export declare const UNREACHED_TIME: Time;
export type OriginNode = {
stopId: StopId;
arrival: Time;
};
export type AccessEdge = {
arrival: Time;
from: StopId;
to: StopId;
duration: Duration;
};
/** A boarded transit trip that carries the passenger from one stop to another. */
export type VehicleEdge = TripStop & {
arrival: Time;
hopOffStopIndex: StopRouteIndex;
/** modeling in-seat transfer */
continuationOf?: VehicleEdge;
};
/** A walking or guaranteed connection between two stops. */
export type TransferEdge = {
arrival: Time;
from: StopId;
to: StopId;
type: TransferType;
minTransferTime?: Duration;
};
export type RoutingEdge = OriginNode | AccessEdge | VehicleEdge | TransferEdge;
/** The earliest arrival at a stop together with how many legs were needed to reach it. */
export type Arrival = {
arrival: Time;
legNumber: number;
};
/**
* Encapsulates all mutable state for a single RAPTOR routing query.
*/
export declare class RoutingState implements IRaptorState {
/** Origin stop IDs for this query. */
origins: StopId[];
/** Destination stop IDs for this query. */
readonly destinations: StopId[];
/**
* Routing graph: the best edge used to reach each stop, per round.
* Indexed as graph[round][stopId]. Entries are undefined for stops not
* reached in that particular round.
*/
readonly graph: (RoutingEdge | undefined)[][];
/**
* Earliest arrival time at each stop (minutes from midnight), indexed by stop ID.
* Pre-filled with UNREACHED_TIME; updated exclusively through updateArrival().
* Not readonly so that fromTestData() can replace the arrays directly.
*/
private earliestArrivalTimes;
/**
* Round number (leg count) in which each stop was first reached, indexed by stop ID.
* Zero-initialized by the typed array; updated exclusively through updateArrival().
* Not readonly so that fromTestData() can replace the arrays directly.
*/
private earliestArrivalLegs;
/**
* Fast O(1) membership test for destination stops.
* Built once at construction time from the `destinations` array.
*/
private readonly destinationSet;
/**
* Cached best arrival time at any destination stop, kept up-to-date by
* {@link updateArrival} so that destination pruning is always O(1).
*/
private _destinationBest;
/**
* Maximum arrival time allowed for this run. Defaults to UNREACHED_TIME when
* the query has no maxDuration limit.
*/
maxArrivalTime: Time;
/**
* Query-level maximum duration, retained so resetFor() can recompute the
* absolute max arrival time for each departure-time iteration.
*/
private readonly maxDuration?;
/**
* Every stop that has received an arrival improvement during the current run,
* in the order the improvements occurred. Used by {@link resetFor} to clear
* only the touched entries instead of scanning the entire array.
*/
private readonly reachedStops;
constructor(departureTime: Time, destinations: StopId[], accessPaths: AccessPoint[], nbStops: number, maxRounds?: number, maxDuration?: Duration);
/**
* Seeds round-0 arrivals and {@link origins} from a set of access paths.
* Called by the constructor and by {@link resetFor}.
* Assumes {@link earliestArrivalTimes} and {@link graph}[0] are already
* allocated and in their "cleared" state (all entries at UNREACHED_TIME /
* undefined) before this method runs.
*/
private seedAccessPaths;
/** Total number of stops in the timetable */
get nbStops(): number;
/**
* Returns the earliest known arrival time at a stop.
* Returns UNREACHED_TIME if the stop has not been reached yet.
*/
arrivalTime(stop: StopId): Time;
/**
* Earliest arrival at any destination stop; {@link UNREACHED_TIME} if none
* has been reached yet. Updated automatically by {@link updateArrival}. O(1).
*/
get destinationBest(): Time;
/**
* In standard RAPTOR the improvement bound is simply the per-run earliest
* arrival; the `round` argument is ignored.
*/
improvementBound(_round: number, stop: StopId): Time;
/** No-op in standard RAPTOR — there are no shared cross-run labels to propagate. */
initRound(_round: number): void;
/**
* Records a new earliest arrival at a stop.
*
* @param stop The stop that was reached.
* @param time The arrival time in minutes from midnight.
* @param leg The round number (number of transit legs taken so far).
*/
updateArrival(stop: StopId, time: Time, leg: number): void;
/**
* Resets this state for a new departure-time iteration **without
* reallocating** the underlying arrays.
*
* Only the stops recorded in {@link reachedStops} are touched — all other
* entries are already at their initial bound values.
*
* After this call the state is equivalent to a freshly constructed
* {@link RoutingState} for the given `depTime` and `accessPaths`.
*
* @param depTime New origin departure time.
* @param accessPaths Access legs for this departure-time slot.
*/
resetFor(depTime: Time, accessPaths: AccessPoint[]): void;
/**
* Iterates over every stop that has been reached, yielding its stop ID,
* earliest arrival time, and the number of legs taken to reach it.
*
* Unreached stops (those still at UNREACHED_TIME) are skipped entirely.
*
* @example
* ```ts
* for (const { stop, arrival, legNumber } of routingState.arrivals()) {
* console.log(`Stop ${stop}: arrived at ${arrival} after ${legNumber} leg(s)`);
* }
* ```
*/
arrivals(): Generator<{
stop: StopId;
arrival: Time;
legNumber: number;
}>;
/**
* Finds the earliest arrival time at any stop from a given set of destinations.
*
* @param routingState The routing state containing arrival times and destinations.
* @returns The earliest arrival time among the provided destinations.
*/
earliestArrivalAtAnyDestination(): Time;
/**
* Returns the earliest arrival at a stop as an {@link Arrival} object,
* or undefined if the stop has not been reached.
*/
getArrival(stop: StopId): Arrival | undefined;
/**
* Returns `true` if `stop` is one of the query's destination stops.
* O(1) — backed by a `Set` built at construction time.
*/
isDestination(stop: StopId): boolean;
/**
* Creates a {@link RoutingState} from fully-specified raw data.
*
* Use this in tests instead of constructing the object through the production
* constructor, which is designed for incremental algorithm state.
*
* @param nbStops Total number of stops (sets array sizes).
* @param origins Origin stop IDs.
* @param destinations Destination stop IDs.
* @param arrivals Each entry is `[stop, time, leg]` — the earliest arrival
* time in minutes and the round number for one stop.
* @param graph One element per round. Each round is a sparse list of
* `[stop, edge]` pairs; stops absent from the list are
* left as `undefined` in the dense output array.
*
* @internal For use in tests only.
*/
static fromTestData({ nbStops, origins, destinations, arrivals, graph, }: {
nbStops: number;
origins?: StopId[];
destinations?: StopId[];
arrivals?: [stop: StopId, time: Time, leg: number][];
graph?: [stop: StopId, edge: RoutingEdge][][];
}): RoutingState;
}