Module extras
This package contains additional functionality that is not a core part of the simulator but rather makes it more convenient to set up and use it. Currently this involves code for performing multiple simulations while varying parameters (“parameter scan”), reading and writing parameter sets and simulation output to and from disk as JSON/JSON Lines. In addition, convenience methods for easily creating graph transport spaces are included.
Simulations and Parameter Scans
This module allows to configure and execute a set of simulations while varying specific parameters, i.e. performing a parameter scan. The typical workflow is as follows:
# create SimulationSet instance
simulation_set = SimulationSet(
base_params={"general": {"n_reqs": 10}},
product_params={"general": {"n_vehicles": [10, 100], "seat_capacity": [2, 8]}},
data_dir=tmp_path,
debug=True,
)
# execute simulations
simulation_set.run()
Parameter Configuration
SimulationSet
takes three main arguments: base_params
, zip_params
and product_params
. Base parameters are parameters which are kept constant across all simulations defined by the simulation set. Here, the values of the inner dict are the actual parameters. For zip and product parameters, lists of values are supplied as the inner dictionary’s values. Zip parameters are varied simultaneously across the simulations, i.e., the first simulation will use the first parameter value for all of the parameters in zip_params
, the second simulation will use the second parameter values, and so on. For zip parameters it is important that all lists of parameter values are of equal length. The lists in product parameters on the other hand will be multiplied as a Cartesian product. Here the lengths do not have to match, all possible combinations will be simulated.
Each of the arguments takes a dictionary of dictionaries. Currently, four top-level keys are supported: general
, dispatcher
, request_generator
, and analytics
. The inner dictionaries contain the actual parameters to be varied. The structure of the outer dictionary is thus as follows:
{
"general": {...},
"dispatcher": {...},
"request_generator": {...},
"analytics": {...},
}
If any of the top-level keys are missing, the respective parameters are taken from the default base parameters.
Currently, the following parameters are supported:
Valid keys for
general
:Either
n_reqs: int
ort_cutoff: float
. If settingt_cutoff
,n_reqs
must be set toNone
and vice versa.Either
n_vehicles: int
andinitial_location: Location
orinitial_locations: dict[ID, Location]
. If settinginitial_locations
,n_vehicles
andinitial_location
must both be set toNone
and vice versa.seat_capacity: int
– Seat capacity of the vehiclesspace: TransportSpace
– The transport space to usetransportation_request_cls: Type[TransportationRequest]
– TheTransportationRequest
class to use (primarily necessary to switch between the Python and Cython implementations)vehicle_state_cls: Type[VehicleState]
– TheVehicleState
class to use (again, primarily necessary to switch between the Python and Cython implementations)fleet_state_cls: Type[FleetState]
– TheFleetState
class to use (again, primarily necessary to switch between the Python and Cython implementations)
Valid values for
dispatcher
:dispatcher_cls: Type[Dispatcher]
– The dispatcher type to useAny dispatcher keyword argument, will be supplied to the dispatcher upon instantiation
Valid values for
request_generator
:request_generator: Type[RequestGenerator]
– The request generator type to useAny request generator keyword argument, will be supplied to the request generator upon instantiation
Valid values for
analytics
:d_avg: float
– Average direct request distance.
As for the top-level keys, if any of the inner keys are missing, the respective parameters are taken from the default base parameters in SimulationSet
, which are currently set as follows:
{
"general": {
"n_reqs": 100,
"t_cutoff": None,
"space": Euclidean2D(coord_range=[(0, 1), (0, 1)], velocity=1),
"n_vehicles": 10,
"initial_location": (0, 0),
"initial_locations": None,
"seat_capacity": 8,
"transportation_request_cls": ridepy.data_structures.TransportationRequest,
"vehicle_state_cls": ridepy.vehicle_state.VehicleState,
"fleet_state_cls": ridepy.fleet_state.SlowSimpleFleetState,
},
"dispatcher": {
"dispatcher_cls": ridepy.util.dispatchers.ridepooling.BruteForceTotalTravelTimeMinimizingDispatcher
},
"request_generator": {
"request_generator_cls": ridepy.util.request_generators.RandomRequestGenerator,
"rate": 1,
},
}
In Cython mode, the respective Cython/C++ implementations of the TransportSpace
, Dispatcher
, TransportationRequest
, and VehicleState
classes are used:
{
"general": {
"n_reqs": 100,
"t_cutoff": None,
"space": Euclidean2D(velocity=1.0),
"n_vehicles": 10,
"initial_location": (0, 0),
"initial_locations": None,
"seat_capacity": 8,
"transportation_request_cls": ridepy.data_structures_cython.data_structures.TransportationRequest,
"vehicle_state_cls": ridepy.vehicle_state_cython.vehicle_state.VehicleState,
"fleet_state_cls": ridepy.fleet_state.SlowSimpleFleetState,
},
"dispatcher": {
"dispatcher_cls": ridepy.util.dispatchers_cython.dispatchers.BruteForceTotalTravelTimeMinimizingDispatcher
},
"request_generator": {
"request_generator_cls": ridepy.util.request_generators.RandomRequestGenerator,
"rate": 1,
},
}
The order of precedence is, last taking highest: default_base_params
, base_params
, zip_params
, product_params
.
Executing simulations
Simulations are executed when SimulationSet.run()
is called. Independent simulations are performed through executing perform_single_simulation()
for each parameter set using multiprocessing. The events that are generated by the simulation are written to disk in the JSON Lines format. The simulation parameters are also written to disk, in separate JSON files. This includes all data necessary to perform the respective simulation. For more detail, see JSON IO. For each simulation run, a unique identfier is generated and the data is stored to <uuid>.jsonl
for the events and <uuid>_params.json
for the simulation parameters. The identifier hashes the parameter set, thereby allowing to continue an interrupted simulation set run later. The IDs generated can be retrieved using SimulationSet.simulation_ids
. Alternatively the filenames of the resulting JSON/JSONL files are also directly available through SimulationSet.param_paths
and SimulationSet.event_paths
.
- class SimulationSet(*, data_dir, base_params=None, zip_params=None, product_params=None, cython=True, debug=False, max_workers=None, process_chunksize=1, jsonl_chunksize=1000, event_path_suffix='.jsonl', param_path_suffix='_params.json', validate=True, comment=None, name=None)[source]
A set of simulations. The parameter space is defined through constant
base_params
, zippedzip_params
and cartesian productproduct_params
. A set of a single simulation is also allowed. ThroughSimulationSet.run
, configurable multiprocessing is implemented, allowing for parallelization of simulation runs at different parameters.- Parameters:
data_dir (str | Path) – Directory in which to store the parameters and events.
base_params (dict[str, dict[str, Any]] | None) – Dictionary setting parameters that are kept constant throughout the simulation set, optional.
zip_params (dict[str, dict[str, Sequence[Any]]] | None) – Dictionary setting parameters that are varied together throughout the simulation set, optional. The values for each inner dict should be lists that all match in lengths.
product_params (dict[str, dict[str, Sequence[Any]]] | None) – Dictionary setting parameters of which the cartesian product (i.e. all possible combinations of the supplied parameters) is created and varied throughout the simulation set, optional.
cython (bool) – Use cython.
debug (bool) – Print debug info.
max_workers (int | None) – Maximum number of multiprocessing workers. Defaults to number of processors on the machine if
None
or not given.process_chunksize (int) – Number of simulations to submit to each multiprocessing worker at a time.
jsonl_chunksize (int) – Maximum number of events to keep in memory before saving to disk
param_path_suffix (str) – Parameters will be stored under “data_dir/<simulation_id><suffix>”
event_path_suffix (str) – Simulation events will be stored under “data_dir/<simulation_id><event_path_suffix>”
validate (bool) – Check validity of the supplied dictionary (unknown outer and inner keys, equal length for
zip_params
)name (str | None) – Optional, filename-safe name.
comment (str | None) – Optional human-readable comment.
- run(dry_run=False, info=False)[source]
Run the simulations configured through
base_params
,zip_params
andproduct_params
using multiprocessing. The parameters and resulting output events are written to disk in JSON/JSON Lines format. For more detail see Executing simulations.- Access simulations results
by id:
SimulationSet.simulation_ids
by parameter file
SimulationSet.param_paths
by event file
SimulationSet.event_paths
- simulation_ids
Get simulation IDs.
- param_paths
Get list of JSON parameter files.
- event_paths
Get list of resulting output event JSON Lines file paths.
- perform_single_simulation(params, *, data_dir, jsonl_chunksize=1000, debug=False, event_path_suffix='.jsonl', param_path_suffix='_params.json', info_path_suffix='_info.json', dry_run=False, info=False, info_contents=None)[source]
Execute a single simulation run based on a parameter dictionary and save parameters and result events to disk.
- Parameters:
params (dict[str, dict[str, Any]]) –
Parameter dictionary to base the simulation on. Must contain the following keys:
general
either
n_reqs
ort_cutoff
seat_capacity
(
initial_location
andn_vehicles
) orinitial_locations
space
transportation_request_cls
vehicle_state_cls
fleet_state_cls
request_generator
request_generator_cls
dispatcher
dispatcher_cls
…
data_dir (Path) – Existing directory in which to store parameters and events.
jsonl_chunksize (int) – Number of simulation events to keep in memory before writing them to disk at once.
debug (bool) – Print debug info to stdout.
param_path_suffix (str) – Parameters will be stored under “data_dir/<simulation_id><suffix>”
event_path_suffix (str) – Simulation events will be stored under “data_dir/<simulation_id><event_path_suffix>”
dry_run (bool) – If True, do not actually simulate. Just pretend to and return the corresponding ID.
info (bool) – Info/benchmark mode. If true, record the time it took to run the simulation run in a separate info file.
info_contents (dict[str, Any] | None) – Additional contents to write to the info file.
info_path_suffix (str)
- Returns:
simulation ID
- Return type:
Running analytics on the simulation results
The simulation results can be automatically analyzed using the ridepy.extras.analytics
module, storing the results to disk.
- SimulationSet.run_analytics(only_stops_and_requests=False, update_existing=False, check_for_changes=True, stops_path_suffix='_stops.pq', requests_path_suffix='_requests.pq', vehicle_quantities_path_suffix='_vehicle_quantities.pq', system_quantities_filename='system_quantities.pq')[source]
Compute analytics from simulation events and store them to disk in parquet format.
- Parameters:
only_stops_and_requests (bool) – Only compute stops and requests, not vehicle and system quantities.
update_existing (bool | list[str]) – Recompute existing outputs. If a list is given, only recompute the list entries. Valid list items are ‘system_quantities’, ‘vehicle_quantities’, ‘stops’, and ‘requests’.
check_for_changes (bool) – If True, only update system quantities if simulation ids have changed. If False, do update system quantities in any case.
stops_path_suffix (str) – Appending this suffix to the simulation ID yields the path to the parquet stops file.
requests_path_suffix (str) – Appending this suffix to the simulation ID yields the path to the parquet requests file.
vehicle_quantities_path_suffix (str) – Appending this suffix to the simulation ID yields the path to the parquet vehicle quantities file.
system_quantities_filename (str) – Filename of the parquet file to store the system quantities in.
- Return type:
None
JSON IO
This IO module implements functionality for reading and writing to JSON/JSON Lines format.
Simulation parameter configurations can be saved and restored using
save_params_json()
and read_params_json()
. The IO module handles serialization and
deserialization of the RequestGenerator
, the dispatcher and the TransportSpace
used for the simulation. This allows to recreate any simulation from its saved parameter
dictionary. Note though that this does not serialize the actual objects. If the
implementation of e.g. the dispatcher is modified, the simulation result will change.
A list of simulation output events can be saved and restored using save_events_json()
and read_events_json()
. The IO module handles serialization and deserialization of
the various event types:
VehicleStateBeginEvent
VehicleStateEndEvent
PickupEvent
DeliveryEvent
RequestSubmissionEvent
RequestAcceptanceEvent
RequestRejectionEvent
Later this can e.g. be used as input for the analytics module:
stops, requests = get_stops_and_requests(
events=read_events_json("events.jsonl"), space=read_params_json("params.json")
)
- class ParamsJSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]
JSONEncoder to use when serializing a dictionary containing simulation parameters. This is able to serialize
RequestGenerator
,TransportSpace
and dispatchers.Example
json.dumps(params, cls=ParamsJSONEncoder)
Constructor for JSONEncoder, with sensible defaults.
If skipkeys is false, then it is a TypeError to attempt encoding of keys that are not str, int, float or None. If skipkeys is True, such items are simply skipped.
If ensure_ascii is true, the output is guaranteed to be str objects with all incoming non-ASCII characters escaped. If ensure_ascii is false, the output can contain non-ASCII characters.
If check_circular is true, then lists, dicts, and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion (which would cause an RecursionError). Otherwise, no such check takes place.
If allow_nan is true, then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders. Otherwise, it will be a ValueError to encode such floats.
If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis.
If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation.
If specified, separators should be an (item_separator, key_separator) tuple. The default is (’, ‘, ‘: ‘) if indent is
None
and (‘,’, ‘: ‘) otherwise. To get the most compact JSON representation, you should specify (‘,’, ‘:’) to eliminate whitespace.If specified, default is a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a
TypeError
.
- class ParamsJSONDecoder(*args, **kwargs)[source]
JSONDecoder to use when deserializing a dictionary containing simulation parameters. This is able to deserialize
RequestGenerator
,TransportSpace
and dispatchers.Example
json.loads(params, cls=ParamsJSONDecoder)
- class EventsJSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]
JSONEncoder to use when serializing a list containing
Event
.Example
json.dumps(events, cls=EventsJSONEncoder)
Constructor for JSONEncoder, with sensible defaults.
If skipkeys is false, then it is a TypeError to attempt encoding of keys that are not str, int, float or None. If skipkeys is True, such items are simply skipped.
If ensure_ascii is true, the output is guaranteed to be str objects with all incoming non-ASCII characters escaped. If ensure_ascii is false, the output can contain non-ASCII characters.
If check_circular is true, then lists, dicts, and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion (which would cause an RecursionError). Otherwise, no such check takes place.
If allow_nan is true, then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders. Otherwise, it will be a ValueError to encode such floats.
If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis.
If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation.
If specified, separators should be an (item_separator, key_separator) tuple. The default is (’, ‘, ‘: ‘) if indent is
None
and (‘,’, ‘: ‘) otherwise. To get the most compact JSON representation, you should specify (‘,’, ‘:’) to eliminate whitespace.If specified, default is a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a
TypeError
.
- sort_params(params)[source]
Returns a copy of the two-level nested dict
params
which is sorted in both levels.
- create_params_json(*, params, sort=True)[source]
Convert a dictionary containing simulation parameters to pretty JSON. Parameter dictionaries may contain anything that is supported by
ParamsJSONEncoder
andParamsJSONDecoder
, e.g.RequestGenerator
,TransportSpace`s and dispatchers. For additional detail, see :ref:`Executing Simulations
.
- save_params_json(*, param_path, params)[source]
Save a dictionary containing simulation parameters to pretty JSON, overwriting existing. Parameter dictionaries may contain anything that is supported by
ParamsJSONEncoder
andParamsJSONDecoder
, e.g.RequestGenerator
,TransportSpace`s and dispatchers. For additional detail, see :ref:`Executing Simulations
.
- read_params_json(param_path)[source]
Read a dictionary containing simulation parameters from JSON. Parameter dictionaries may contain anything that is supported by
ParamsJSONEncoder
andParamsJSONDecoder
, e.g.RequestGenerator
,TransportSpace`s and dispatchers. For additional detail, see :ref:`Executing Simulations
.
- save_events_json(*, jsonl_path, events)[source]
Save events iterable to a file according to JSONL specs, appending to existing. For additional detail, see Executing simulations.
- read_events_json(jsonl_path)[source]
Read events from JSON lines file, where each line of the file contains a single event. For additional detail, see Executing simulations.
Spaces
This module implements thin convenience wrappers around networkx
to create common
network topologies to be used as transport spaces.
- make_nx_grid(dim=(3, 3), periodic=False, edge_distance=1)[source]
Return a lattice
nx.Graph
Use in conjunction with
spaces.Graph
orspaces_cython.Graph
likeGraph.from_nx(make_nx_grid())
- make_nx_cycle_graph(order=10, edge_distance=1)[source]
Return a cyclic
nx.Graph
Use in conjunction with
spaces.Graph
orspaces_cython.Graph
likeGraph.from_nx(make_nx_cycle_graph())