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)
Example #3
0
    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
Example #4
0
 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)
Example #5
0
    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)