Introduction
RidePy lets a user specify a FleetState of \(n\) vehicles with desired
passenger capacities, as well as an iterator of TransportationRequest
objects, each containing:
request_idcreation_timestamporigindestinationpickup_timewindow_minpickup_timewindow_maxdelivery_timewindow_mindelivery_timewindow_max
The request iterator must yield requests in increasing order of creation_timestamp.
Calling FleetState.simulate() then executes the simulation, which outputs a
sequence of Event objects (add link here), from which the user can compute various metrics,
optionally using the util.analytics module.
The stoplist
FleetState contains a dictionary fleet, which maps a vehicle_id to a
VehicleState. A VehicleState, in turn holds the future trajectory of the
vehicle in the form of a Stoplist: a list of Stop objects containing:
location,requestto be serviced,action: one ofpickup,dropofforinternal,estimated_arrival_time,occupancy_after_servicing,time_window_min,time_window_max.
Therefore, a Stoplist contains all the information on where the vehicle will
go and what it will do in the future (if the stoplist does not change in the
meantime, by e.g. a dispatcher inserting a new TransportationRequest s
pickup and dropoff in it).
The CPE Stop
The first element of any vehicle’s Stoplist is a Stop object that is
called the “CPE stop” (current position element), signifying the immediate
position of the vehicle. It is not associated with any TransportationRequest.
The estimated_arrival_time of this stop defines the time at which the
vehicle is at the CPEs location. This is always roughly the current location
and time, though it might be immediate past (before it has been updated to the
current state) or immediate future (when the vehicle is in between two adjacent nodes
on a graph, see TransportSpace.interp_time).
The Simulation run: advancing the internal clock
When a FleetState is created, an internal “clock” is started at time \(t= 0\).
When the simulation is run,
The next request
ris fetched from the request iterator.The simulator’s internal clock is advanced to the
creation_timestampofr. For each vehicleAll the stops whose
estimated_arrival_timeis less than the current timestamp is removed. For each of these stops an appropriatePickupEventorDeliveryEventis emitted.Based on its
Stoplist, its “current” position is inferred, and thelocationandestimated_arrival_timeof its CPE stop are modified accordingly.
The vehicle that is “best suited” for transporting
ris determined by thedispatcher, and two new stops are inserted into itsStoplist: the pickup and dropoff ofr. We describe below how this choice is made. ARequestAcceptanceEventis emitted. If no such vehicle is found, aRequestRejectionEventis emitted instead.The previous steps are repeated until either the request iterator is exhausted or a time cutoff is reached.
The dispatcher
The dispatcher determines which vehicle should service a certain request, and in which order it should service the requests assigned to it. ridepy defines a clean interface enabling the users to create their own dispatchers. A number of predefined ones are available in`.util.dispatchers`.
When a new TransportationRequest needs to be processed:
The
dispatcheris called for each vehicle, which can be thought of as the mapping(new_request, stoplist) ⇒ (cost, new_stoplist). It
Checks if the pickup and dropoff of
rcan be inserted to the vehicle’sStoplistwithout violating
The new request’s
pickup_timewindow_min|maxanddelivery_timewindow_min|max.The
time_window_min|maxof every existing stop in the stoplist of the vehicle.The capacity contraints of the vehicle.
The implicit constraint of inserting Pickup, with regards to order, before Dropoff
There can be multiple possible insertions that do not violate any of these constraints. The dispatcher computes a numerical cost for each possible insertion and chooses the insertion with the least cost. One such cost could be the total detour caused by an insertion, for example.
If no insertion is found for a vehicle, the dispatcher returns a cost of \(\infty\).
If more than one vehicle can service the request, then the one with minimum cost is chosen. That is, its
Stoplistis changed to thenew_stoplistreturned by the dispatcher.
The dispatcher is solely responsible for keeping the stoplist in a internally valid state, as the one with minimal cost substitutes the original one for the respective vehicle. Constraints are not checked again elsewhere. This incorporates in particular estimated arrival times which are constrained by the travel time on the transport space.
The Transport Space
The transport space defines the space that stops and requests live on. This has primarily three implications:
It defines the coordinates used for specifying locations. This can e.g. be an integer number for graph vertices, or a pair of floats for a continuous two-dimensional space.
The first key function that the
TransportSpaceprovides is a metric \(T\times T\rightarrow\mathbb R, (u,v)\mapsto d(u,v)`\) which yields the distance between locations. In addition, the same is provided for the travel time, which takes the velocity at which the vehicle moves into account.The second function is
interp_dist(u,v, time_to_dest), and respectivelyinterp_time. This interpolates a location on the space on the route between two pointsuandv, with the know remaining timetime_to_dest. This is used to determine the current location of the vehicle when it is known that the vehicle is on the way tov, having started atu, and with remainingtime_to_dest = next_stop.estimated_arrival_time - current_time.