def _apply_cutoff(self, cutoff_distance): for block in list(self._profile_blocks): block_max = max(block.distance_start, block.distance_end) if block_max > cutoff_distance: print("applying cutoff") blocks = [] if block.distance_start == block.distance_end or \ (block.distance_start > cutoff_distance and block.distance_end > cutoff_distance): blocks.append( ProfileBlock(distance_end=cutoff_distance, distance_start=cutoff_distance, start_time=block.start_time, end_time=block.end_time)) else: if (block.distance_end >= cutoff_distance): assert (block.distance_end < cutoff_distance) split_point_x = block.start_time + ( block.distance_start - cutoff_distance) / ( block.distance_start - block.distance_end) * block.width() if block.distance_start > block.distance_end: start_distance = cutoff_distance end_distance = block.distance_end else: start_distance = block.distance_start end_distance = cutoff_distance first_block = ProfileBlock(block.start_time, split_point_x, start_distance, cutoff_distance) second_block = ProfileBlock(split_point_x, block.end_time, cutoff_distance, end_distance) blocks.append(first_block) blocks.append(second_block) index = self._profile_blocks.index(block) self._profile_blocks[index:index + 1] = blocks
def test_interpolate(self): blocks = [ProfileBlock(0, 1, 2, 1), ProfileBlock(1, 2, 2, 2)] analyzer = ProfileBlockAnalyzer(blocks, cutoff_distance=3.0) self.assertAlmostEqual(analyzer.interpolate(0.2), 1.8) self.assertAlmostEqual(analyzer.interpolate(1-10**-9), 1.) self.assertAlmostEqual(analyzer.interpolate(1), 1) self.assertAlmostEqual(analyzer.interpolate(1.+10**-9), 2) self.assertAlmostEqual(analyzer.interpolate(1.23), 2) self.assertAlmostEqual(analyzer.interpolate(2), 2)
def get_fastest_path_temporal_distance_blocks(self): """ Returns ------- blocks: list[ProfileBlock] """ def _label_to_prop_dict(label): return {prop: getattr(label, prop) for prop in self.label_props} labels = self._fastest_path_labels for i in range(len(labels) - 1): assert (labels[i].departure_time < labels[i + 1].departure_time) previous_dep_time = self.start_time_dep blocks = [] for label in labels: if previous_dep_time >= self.end_time_dep: break end_time = min(label.departure_time, self.end_time_dep) assert (end_time >= previous_dep_time) temporal_distance_start = label.duration() + ( label.departure_time - previous_dep_time) if temporal_distance_start > self.walk_duration: split_point_x_computed = label.departure_time - ( self.walk_duration - label.duration()) split_point_x = min(split_point_x_computed, end_time) if previous_dep_time < split_point_x: # add walk block, only if it is required walk_block = ProfileBlock(previous_dep_time, split_point_x, self.walk_duration, self.walk_duration, **_label_to_prop_dict(label)) blocks.append(walk_block) if split_point_x < end_time: trip_block = ProfileBlock( split_point_x, end_time, label.duration() + (end_time - split_point_x), label.duration(), **_label_to_prop_dict(label)) blocks.append(trip_block) else: journey_block = ProfileBlock( previous_dep_time, end_time, temporal_distance_start, temporal_distance_start - (end_time - previous_dep_time), **_label_to_prop_dict(label)) blocks.append(journey_block) previous_dep_time = blocks[-1].end_time if previous_dep_time < self.end_time_dep: last_block = ProfileBlock(previous_dep_time, self.end_time_dep, self.walk_duration, self.walk_duration) blocks.append(last_block) return blocks
def get_prop_analyzer_for_pre_journey_wait(self): kwargs = self.kwargs prop_blocks = [] fp_blocks = self.get_fastest_path_temporal_distance_blocks() for b in fp_blocks: if b.distance_end == float("inf"): prop_block = b elif b.is_flat(): prop_block = ProfileBlock(b.start_time, b.end_time, 0, 0) else: prop_block = ProfileBlock(b.start_time, b.end_time, b.width(), 0) prop_blocks.append(prop_block) return ProfileBlockAnalyzer(prop_blocks, **kwargs)
def get_prop_analyzer_flat(self, property, value_no_next_journey, value_cutoff): """ Get a journey property analyzer, where each journey is weighted by the number of. Parameters ---------- property: string Name of the property, needs to be one of label_props given on initialization. value_no_next_journey: Value of the profile, when there is no next journey available. value_cutoff: number default value of the property when cutoff is applied Returns ------- ProfileBlockAnalyzer """ kwargs = self.kwargs fp_blocks = self.get_fastest_path_temporal_distance_blocks() prop_blocks = [] for b in fp_blocks: if b.is_flat(): if b.distance_end == self.walk_duration and b.distance_end != float( 'inf'): prop_value = value_cutoff else: prop_value = value_no_next_journey else: prop_value = b[property] prop_block = ProfileBlock(b.start_time, b.end_time, prop_value, prop_value) prop_blocks.append(prop_block) return ProfileBlockAnalyzer(prop_blocks, **kwargs)
def __init__(self, labels, walk_time_to_target, start_time_dep, end_time_dep): """ Initialize the data structures required by Parameters ---------- node_profile: NodeProfileSimple """ self.start_time_dep = start_time_dep self.end_time_dep = end_time_dep # used for computing temporal distances: all_pareto_optimal_tuples = [ pt for pt in labels if (start_time_dep < pt.departure_time < end_time_dep) ] labels_after_dep_time = [ label for label in labels if label.departure_time >= self.end_time_dep ] if labels_after_dep_time: next_label_after_end_time = min( labels_after_dep_time, key=lambda el: el.arrival_time_target) all_pareto_optimal_tuples.append(next_label_after_end_time) all_pareto_optimal_tuples = sorted( all_pareto_optimal_tuples, key=lambda ptuple: ptuple.departure_time) arrival_time_target_at_end_time = end_time_dep + walk_time_to_target previous_trip = None for trip_tuple in all_pareto_optimal_tuples: if previous_trip: assert (trip_tuple.arrival_time_target > previous_trip.arrival_time_target) if trip_tuple.departure_time > self.end_time_dep \ and trip_tuple.arrival_time_target < arrival_time_target_at_end_time: arrival_time_target_at_end_time = trip_tuple.arrival_time_target previous_trip = trip_tuple self._walk_time_to_target = walk_time_to_target self._profile_blocks = [] previous_departure_time = start_time_dep self.trip_durations = [] self.trip_departure_times = [] for trip_pareto_tuple in all_pareto_optimal_tuples: if trip_pareto_tuple.departure_time > self.end_time_dep: continue if self._walk_time_to_target <= trip_pareto_tuple.duration(): print(self._walk_time_to_target, trip_pareto_tuple.duration()) assert (self._walk_time_to_target > trip_pareto_tuple.duration()) effective_trip_previous_departure_time = max( previous_departure_time, trip_pareto_tuple.departure_time - (self._walk_time_to_target - trip_pareto_tuple.duration())) if effective_trip_previous_departure_time > previous_departure_time: walk_block = ProfileBlock( start_time=previous_departure_time, end_time=effective_trip_previous_departure_time, distance_start=self._walk_time_to_target, distance_end=self._walk_time_to_target) self._profile_blocks.append(walk_block) trip_waiting_time = trip_pareto_tuple.departure_time - effective_trip_previous_departure_time trip_block = ProfileBlock( end_time=trip_pareto_tuple.departure_time, start_time=effective_trip_previous_departure_time, distance_start=trip_pareto_tuple.duration() + trip_waiting_time, distance_end=trip_pareto_tuple.duration()) self.trip_durations.append(trip_pareto_tuple.duration()) self.trip_departure_times.append(trip_pareto_tuple.departure_time) self._profile_blocks.append(trip_block) previous_departure_time = trip_pareto_tuple.departure_time # deal with last (or add walking block like above) if not self._profile_blocks or self._profile_blocks[ -1].end_time < end_time_dep: if len(self._profile_blocks) > 0: dep_previous = self._profile_blocks[-1].end_time else: dep_previous = start_time_dep waiting_time = end_time_dep - dep_previous distance_end_trip = arrival_time_target_at_end_time - end_time_dep walking_wait_time = min( end_time_dep - dep_previous, waiting_time - (self._walk_time_to_target - distance_end_trip)) walking_wait_time = max(0, walking_wait_time) if walking_wait_time > 0: walk_block = ProfileBlock( start_time=dep_previous, end_time=dep_previous + walking_wait_time, distance_start=self._walk_time_to_target, distance_end=self._walk_time_to_target) assert (walk_block.start_time <= walk_block.end_time) assert (walk_block.distance_end <= walk_block.distance_start) self._profile_blocks.append(walk_block) trip_waiting_time = waiting_time - walking_wait_time if trip_waiting_time > 0: try: trip_block = ProfileBlock( start_time=dep_previous + walking_wait_time, end_time=dep_previous + walking_wait_time + trip_waiting_time, distance_start=distance_end_trip + trip_waiting_time, distance_end=distance_end_trip) assert (trip_block.start_time <= trip_block.end_time) assert (trip_block.distance_end <= trip_block.distance_start) self._profile_blocks.append(trip_block) except AssertionError as e: # the error was due to a very small waiting timesmall numbers assert (trip_waiting_time < 10**-5) # TODO? Refactor to use the cutoff_distance feature in ProfileBlockAnalyzer? self.profile_block_analyzer = ProfileBlockAnalyzer( profile_blocks=self._profile_blocks)