def run_router_with_reconstruction_test(router_type, from_stop, to_stop, des_dep_time_hhmmss, exp_nb_legs, exp_nb_pt_legs, exp_first_stop, exp_last_stop, exp_dep_time_hhmmss, exp_arr_time_hhmmss, exp_pt_in_stops, exp_pt_out_stops): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) router = None if router_type == RouterWithReconstructionType.UNOPTIMIZED_EARLIEST_ARRIVAL_WITH_RECONSTRUCTION: router = cs_core.route_earliest_arrival_with_reconstruction elif router_type == RouterWithReconstructionType.OPTIMIZED_EARLIEST_ARRIVAL_WITH_RECONSTRUCTION: router = cs_core.route_optimized_earliest_arrival_with_reconstruction else: ValueError("router not known") journey = router(from_stop.id, to_stop.id, hhmmss_to_sec(des_dep_time_hhmmss)) assert exp_nb_legs == journey.get_nb_journey_legs() assert exp_nb_pt_legs == journey.get_nb_pt_journey_legs() assert (exp_first_stop.id if exp_first_stop is not None else None) == journey.get_first_stop_id() assert (exp_last_stop.id if exp_last_stop is not None else None) == journey.get_last_stop_id() assert (exp_dep_time_hhmmss if exp_dep_time_hhmmss else None) == seconds_to_hhmmss(journey.get_dep_time()) assert (exp_arr_time_hhmmss if exp_arr_time_hhmmss else None) == seconds_to_hhmmss(journey.get_arr_time()) assert [s.id for s in exp_pt_in_stops] == journey.get_pt_in_stop_ids() assert [s.id for s in exp_pt_out_stops] == journey.get_pt_out_stop_ids()
def __init__(self, in_connection, out_connection, footpath): if in_connection is None and out_connection is None and footpath is None: raise ValueError( "either in_connection and out_connection or footpath or all three must be not None" ) if (in_connection is None and out_connection is not None) or ( in_connection is not None and out_connection is None): raise ValueError( "in_connection {} and out_connection {} must both either be None or not None" .format(in_connection, out_connection)) if in_connection is not None and out_connection is not None: if in_connection.trip_id != out_connection.trip_id: raise ValueError( "trip_id {} of in_connection is not equal to trip_id {} of out_connection." .format(in_connection.trip_id, out_connection.trip_id)) if in_connection != out_connection: if in_connection.dep_time > out_connection.arr_time: raise ValueError( "dep_time {} of in_connection is after arr_time {} of out_connection." .format(seconds_to_hhmmss(in_connection.dep_time), seconds_to_hhmmss(out_connection.arr_time))) if footpath is not None and out_connection is not None: if out_connection.to_stop_id != footpath.from_stop_id: raise ValueError( "to_stop_id {} of out_connection is not equal to from_stop_id {} of footpath" .format(out_connection.to_stop_id, footpath.from_stop_id)) self.in_connection = in_connection self.out_connection = out_connection self.footpath = footpath
def __str__(self): return ( "[id={}, trip_type={}, first_stop_id={}, last_stop_id={}, dep_in_first_stop={}, " "arr_in_last_stop={}, #connections={}]").format( self.id, self.trip_type, self.connections[0].from_stop_id if self.connections else "", self.connections[-1].to_stop_id if self.connections else "", seconds_to_hhmmss(self.connections[0].dep_time) if self.connections else "", seconds_to_hhmmss(self.connections[-1].arr_time) if self.connections else "", len(self.connections))
def test_unoptimized_earliest_arrival_bern_zuerich_hb(): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) assert "08:58:00" == seconds_to_hhmmss( cs_core.route_earliest_arrival(bern.id, zuerich_hb.id, hhmmss_to_sec("07:35:00"))) assert "08:58:00" == seconds_to_hhmmss( cs_core.route_earliest_arrival(bern.id, zuerich_hb.id, hhmmss_to_sec("08:02:00"))) assert cs_core.route_earliest_arrival(bern.id, zuerich_hb.id, hhmmss_to_sec("23:33:00")) is None
def test_create_trips(): dep_first_trip_first_stop = 5 * 60 * 60 + 42 * 60 trips_fri_sg = create_trips( [fribourg, bern, zuerich_hb, winterthur, st_gallen], [14 * 60, 58 * 60, 20 * 60, 38 * 60], [6 * 60, 5 * 60, 3 * 60], dep_first_trip_first_stop, 32, 30 * 60) assert len(trips_fri_sg) == 32 assert "1" == trips_fri_sg[3].connections[0].from_stop_id assert "2" == trips_fri_sg[3].connections[0].to_stop_id assert "2" == trips_fri_sg[3].connections[1].from_stop_id assert "3" == trips_fri_sg[3].connections[1].to_stop_id assert "4" == trips_fri_sg[3].connections[-1].from_stop_id assert "5" == trips_fri_sg[3].connections[-1].to_stop_id assert "08:12:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[0].dep_time) assert "08:26:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[0].arr_time) assert "08:32:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[1].dep_time) assert "09:30:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[1].arr_time) assert "09:35:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[2].dep_time) assert "09:55:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[2].arr_time) assert "09:58:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[3].dep_time) assert "10:36:00" == seconds_to_hhmmss( trips_fri_sg[5].connections[3].arr_time)
def test_unoptimized_earliest_arrival_with_reconstruction_by_name_bern_bahnhof_samedan_bahnhof( ): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) journey = cs_core.route_earliest_arrival_with_reconstruction_by_name( bern_bahnhof.name, samedan_bahnhof.name, "08:26:00") assert 4 == journey.get_nb_journey_legs() assert 3 == journey.get_nb_pt_journey_legs() assert bern_bahnhof.id == journey.get_first_stop_id() assert samedan_bahnhof.id == journey.get_last_stop_id() assert "08:27:00" == seconds_to_hhmmss(journey.get_dep_time()) assert "12:48:00" == seconds_to_hhmmss(journey.get_arr_time()) assert [bern.id, zuerich_hb.id, chur.id] == journey.get_pt_in_stop_ids() assert [zuerich_hb.id, chur.id, samedan.id] == journey.get_pt_out_stop_ids()
def test_unoptimized_earliest_arrival_bern_duebystrasse_ostermundigen_bahnhof( ): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) assert "12:34:00" == seconds_to_hhmmss( cs_core.route_earliest_arrival(bern_duebystrasse.id, ostermundigen_bahnhof.id, hhmmss_to_sec("12:09:46")))
def test_unoptimized_earliest_arrival_bern_samedan(): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) assert "12:45:00" == seconds_to_hhmmss( cs_core.route_earliest_arrival(bern.id, samedan.id, hhmmss_to_sec("08:30:00"))) assert cs_core.route_earliest_arrival(bern.id, samedan.id, hhmmss_to_sec("21:00:00")) is None
def route_earliest_arrival(self, from_stop_id, to_stop_id, desired_dep_time): """Executes the unoptimized earliest arrival version (figure 3 of https://arxiv.org/pdf/1703.05997.pdf) of the connection scan algorithm from the source to the target stop respecting the desired departure time. Note: - In order to correctly model the footpaths at the start and end of the journey, the algorithm from the pseudo code is slightly modified. - the data structures are not optimized for performance. Args: from_stop_id (str): id of the source stop. to_stop_id (str): id of the target stop. desired_dep_time (int): desired departure time in seconds after midnight. Returns: int: earliest possible arrival time at the target stop. """ log_start( "unoptimized earliest arrival routing from {} to {} at {}".format( self.connection_scan_data.stops_per_id[from_stop_id].name, self.connection_scan_data.stops_per_id[to_stop_id].name, seconds_to_hhmmss(desired_dep_time)), log) # TODO implement task 1 here # Some hints: # - First get familiar with the data structures from the classes module and the ConnectionScanData class # - In order to correctly model the footpaths at the start and end of the journey, # the algorithm from the pseudo code must be slightly modified. # - You could use the following dynamic data structures: # - a dict for the earliest arrival including transfer/walking times per stop. # - a int for the earliest arrival time at the target stop. # - a dict to mark if a trip is set or not. res = -1 log_end(additional_message="earliest arrival time: {}".format( seconds_to_hhmmss(res) if res else res)) return res
def route_earliest_arrival_with_reconstruction(self, from_stop_id, to_stop_id, desired_dep_time): """Executes the unoptimized earliest arrival with reconstruction version (figure 6 of https://arxiv.org/pdf/1703.05997.pdf) of the connection scan algorithm from the source to the target stop respecting the desired departure time. Note: - In order to correctly model the footpaths at the start and end of the journey, the algorithm from the pseudo code is slightly modified. - the data structures are not optimized for performance. Args: from_stop_id (str): id of the source stop. to_stop_id (str): id of the target stop. desired_dep_time (int): desired departure time in seconds after midnight. Returns: Journey: a Journey with earliest possible arrival time from the source to the target stop. """ log_start( "unoptimized earliest arrival routing with journey reconstruction from {} to {} at {}" .format(self.connection_scan_data.stops_per_id[from_stop_id].name, self.connection_scan_data.stops_per_id[to_stop_id].name, seconds_to_hhmmss(desired_dep_time)), log) # TODO implement task 2 here # Some hints: # - Implement task 1 first. # - In order to correctly model the footpaths at the start and end of the journey, # the algorithm from the pseudo code must be slightly modified. # - You could use the following dynamic data structures: # - a dict for the earliest arrival including transfer/walking times per stop. # - a int for the earliest arrival time at the target stop. # - a dict for the in/boarding connection per trip. # - a JourneyLeg for the last journey leg at the target stop. # - Construct the resulting Journey with the reconstruction logic from the pseudo code. res = Journey() log_end(additional_message="# journey legs: {}".format( 0 if res is None else res.get_nb_journey_legs())) return res
def create_trips(stops, running_times, stop_times, first_departure, nb_trips, headway): trips = [] for trip_index in range(nb_trips): dep_first_stop = first_departure + trip_index * headway trip_id = "{}_{}_{}_{}".format(stops[0].name, stops[-1].name, seconds_to_hhmmss(dep_first_stop), trip_index) cons = [] arr = None for stop_index in range(len(stops) - 1): dep = dep_first_stop if stop_index == 0 else arr + stop_times[ stop_index - 1] arr = dep + running_times[stop_index] cons += [ Connection(trip_id, stops[stop_index].id, stops[stop_index + 1].id, dep, arr) ] trips += [Trip(trip_id, cons)] return trips
def route_optimized_earliest_arrival_with_reconstruction( self, from_stop_id, to_stop_id, desired_dep_time): """Executes the optimized earliest arrival with reconstruction version (figure 4 and 6 of https://arxiv.org/pdf/1703.05997.pdf) of the connection scan algorithm from the source to the target stop respecting the desired departure time. Note: - In order to correctly model the footpaths at the start and end of the journey, the algorithm from the pseudo code is slightly modified. - the data structures are not optimized for performance. Args: from_stop_id (str): id of the source stop. to_stop_id (str): id of the target stop. desired_dep_time (int): desired departure time in seconds after midnight. Returns: Journey: a Journey with earliest possible arrival time from the source to the target stop. """ log_start( "optimized earliest arrival routing with journey reconstruction from {} to {} at {}" .format(self.connection_scan_data.stops_per_id[from_stop_id].name, self.connection_scan_data.stops_per_id[to_stop_id].name, seconds_to_hhmmss(desired_dep_time)), log) # TODO implement task 3 here # Some hints: # - Implement task 2 first. # - In order to correctly model the footpaths at the start and end of the journey, # the algorithm from the pseudo code must be slightly modified. # - You could use the same dynamic data structures and reconstruction logic as in task 2. # - Implement the three optimization criterion's described in the paper (on page 8): # stopping criterion, starting criterion and limited walking. # For the starting criterion you can use the function binary_search from the funs module. res = Journey() log_end(additional_message="# journey legs: {}".format( 0 if res is None else res.get_nb_journey_legs())) return res
def __str__(self): return "[trip_id={}, from_stop_id={}, to_stop_id={}, dep_time={}, arr_time={}]".format( self.trip_id, self.from_stop_id, self.to_stop_id, seconds_to_hhmmss(self.dep_time), seconds_to_hhmmss(self.arr_time))
def test_unoptimized_earliest_arrival_by_name_bern_bern_bahnhof(): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) assert "12:14:46" == seconds_to_hhmmss( cs_core.route_earliest_arrival_by_name(bern.name, bern_bahnhof.name, "12:09:46"))
def test_unoptimized_earliest_arrival_bern_bern(): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) assert "12:09:46" == seconds_to_hhmmss( cs_core.route_earliest_arrival(bern.id, bern.id, hhmmss_to_sec("12:09:46")))
def test_unoptimized_earliest_arrival_basel_st_gallen(): cs_data = create_test_connectionscan_data() cs_core = ConnectionScanCore(cs_data) assert "09:41:00" == seconds_to_hhmmss( cs_core.route_earliest_arrival(basel_sbb.id, st_gallen.id, hhmmss_to_sec("07:30:00")))
def __str__(self): return "[trip_id={}, in_stop_id={}, out_stop_id={}, dep_time={}, arr_time={}]".format( self.get_trip_id(), self.get_in_stop_id(), self.get_out_stop_id(), seconds_to_hhmmss(self.get_dep_time_in_stop_id()), seconds_to_hhmmss(self.get_arr_time_out_stop_id()))
def test_seconds_to_hhmmss(): assert "00:00:00" == seconds_to_hhmmss(0.012879) assert "00:00:02" == seconds_to_hhmmss(2.012379) assert "03:05:02" == seconds_to_hhmmss(3 * 60 * 60 + 5 * 60 + 2 + 0.112) assert "03:05:02" == seconds_to_hhmmss(3 * 60 * 60 + 5 * 60 + 2)