コード例 #1
0
class LookAheadHandler(object):
    def __init__(self):
        self.mongodb_database_connection = MongodbDatabaseConnection(host=mongodb_host, port=mongodb_port)
        log(module_name='look_ahead_handler', log_type='DEBUG',
            log_message='mongodb_database_connection: established')

    def generate_bus_line(self, bus_stop_names, bus_line_id=None):
        """
        Generate a bus_line, consisted of a bus_line_id and a list of bus_stops, and store it to the corresponding
        collection of the System Database. Moreover, identify all the possible waypoints between the bus_stops
        of the bus_line, and populate the BusStopWaypoints collection.

        :param bus_stop_names: [string]
        :param bus_line_id: int
        :return: None
        """
        # 1: The inputs: bus_line_id and bus_stop_names are provided to the function, so as as a bus_line
        #    with the corresponding bus_line_id and bus_stops to be generated.
        #
        # 2: The Look Ahead connects to the System Database and retrieves the bus_stops which correspond to
        #    the provided bus_stop_names. The function returns None and the bus_line is not generated,
        #    in case there is a bus_stop_name which does not correspond to a stored bus_stop.
        #
        if bus_line_id is None:
            maximum_bus_line_id = self.mongodb_database_connection.get_maximum_or_minimum(collection='bus_line')
            bus_line_id = maximum_bus_line_id + 1

        bus_stops = []

        for bus_stop_name in bus_stop_names:
            bus_stop_document = self.mongodb_database_connection.find_bus_stop_document(name=bus_stop_name)

            if bus_stop_document is None:
                log_message = 'find_bus_stop_document (mongodb_database) - name:', bus_stop_name, '- result: None'
                log(module_name='look_ahead_handler', log_type='DEBUG', log_message=log_message)
                return None
            else:
                bus_stops.append(bus_stop_document)

        # 3: The intermediate waypoints of the bus_routes, which are generated while combining starting and
        #    ending bus_stops of the bus_line, should be stored as bus_stop_waypoints_documents at the System Database.
        #    The Look Ahead checks the existing bus_stop_waypoints_documents and communicates with the Route Generator
        #    in order to identify the waypoints of the bus_routes which are not already stored. The newly generated
        #    bus_stop_waypoints_documents are getting stored to the corresponding collection of the System Database.
        #    The function returns None and the bus_line is not generated, in case the Route Generator can not identify
        #    a possible route in order to connect the bus_stops of the bus_line.
        #
        number_of_bus_stops = len(bus_stops)

        for i in range(0, number_of_bus_stops - 1):
            starting_bus_stop = bus_stops[i]
            ending_bus_stop = bus_stops[i + 1]

            bus_stop_waypoints_document = self.mongodb_database_connection.find_bus_stop_waypoints_document(
                starting_bus_stop=starting_bus_stop,
                ending_bus_stop=ending_bus_stop
            )
            if bus_stop_waypoints_document is None:
                route_generator_response = get_waypoints_between_two_bus_stops(
                    starting_bus_stop=starting_bus_stop,
                    ending_bus_stop=ending_bus_stop
                )
                if route_generator_response is None:
                    log(module_name='look_ahead_handler', log_type='DEBUG',
                        log_message='get_waypoints_between_two_bus_stops (route_generator): None')
                    return None
                else:
                    waypoints = route_generator_response.get('waypoints')

                    if len(waypoints) == 0:
                        log(module_name='look_ahead_handler', log_type='DEBUG',
                            log_message='get_waypoints_between_two_bus_stops (route_generator): None')
                        return None

                    lists_of_edge_object_ids = []

                    for list_of_edges in waypoints:
                        list_of_edge_object_ids = []

                        for edge in list_of_edges:
                            edge_object_id = edge.get('_id')
                            list_of_edge_object_ids.append(edge_object_id)

                        lists_of_edge_object_ids.append(list_of_edge_object_ids)

                    # waypoints: [[edge_object_id]]
                    #
                    waypoints = lists_of_edge_object_ids

                    self.mongodb_database_connection.insert_bus_stop_waypoints_document(
                        starting_bus_stop=starting_bus_stop,
                        ending_bus_stop=ending_bus_stop,
                        waypoints=waypoints
                    )

        # 4: The Look Ahead stores the newly generated bus_line_document, which is consisted of the bus_line_id
        #    and the list of bus_stops, to the corresponding collection of the System Database.
        #    In case there is an already existing bus_line_document, with the same bus_line_id,
        #    then the list of bus_stops gets updated.
        #
        bus_line_document = {'bus_line_id': bus_line_id, 'bus_stops': bus_stops}
        self.mongodb_database_connection.insert_bus_line_document(bus_line_document=bus_line_document)

        log(module_name='look_ahead_handler', log_type='DEBUG',
            log_message='insert_bus_line_document (mongodb_database): ok')

    def generate_timetables_for_bus_line(self, timetables_starting_datetime, timetables_ending_datetime,
                                         requests_min_departure_datetime, requests_max_departure_datetime,
                                         bus_line=None, bus_line_id=None):
        """
        Generate timetables for a bus_line, for a selected datetime period,
        evaluating travel_requests of a specific datetime period.

        - The input: timetables_starting_datetime and input: timetables_ending_datetime
          are provided to the function, so as timetables for the specific datetime period
          to be generated.

        - The input: requests_min_departure_datetime and input: requests_max_departure_datetime
          are provided to the function, so as travel_requests with departure_datetime corresponding
          to the the specific datetime period to be evaluated.

        - The input: bus_line or input: bus_line_id is provided to the function,
          so as timetables for the specific bus_line to be generated.

        :param timetables_starting_datetime: datetime
        :param timetables_ending_datetime: datetime
        :param requests_min_departure_datetime: datetime
        :param requests_max_departure_datetime: datetime
        :param bus_line: bus_line_document
        :param bus_line_id: int
        :return: None
        """

        maximum_timetable_id_in_database = self.mongodb_database_connection.get_maximum_or_minimum(
            collection='timetable'
        )

        # 1: The list of bus_stops corresponding to the provided bus_line is retrieved.
        #
        # bus_stop_document: {
        #     '_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}
        # }
        # bus_stops: [bus_stop_document]
        #
        if bus_line is None and bus_line_id is None:
            return None
        elif bus_line is None:
            bus_line = self.mongodb_database_connection.find_bus_line_document(bus_line_id=bus_line_id)
        else:
            bus_line_id = bus_line.get('bus_line_id')

        bus_stops = bus_line.get('bus_stops')

        # 2: The Look Ahead retrieves from the System Database the travel_requests with
        #    departure_datetime higher than requests_min_departure_datetime and
        #    lower than requests_max_departure_datetime.
        #
        # travel_request_document: {
        #     '_id', 'client_id', 'bus_line_id',
        #     'starting_bus_stop': {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}},
        #     'ending_bus_stop': {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}},
        #     'departure_datetime', 'arrival_datetime'
        # }
        # travel_requests: [travel_request_document]
        #
        travel_requests = self.mongodb_database_connection.find_travel_request_documents(
            bus_line_ids=[bus_line_id],
            min_departure_datetime=requests_min_departure_datetime,
            max_departure_datetime=requests_max_departure_datetime
        )

        # 3: (TimetableGenerator is initialized) The Look Ahead sends a request to the Route Generator so as
        #    to identify the less time-consuming bus_route between the bus_stops of bus_line,
        #    while taking into consideration the current levels of traffic density.
        #
        timetable_generator = TimetableGenerator(
            maximum_timetable_id_in_database=maximum_timetable_id_in_database,
            bus_line_id=bus_line_id,
            bus_stops=bus_stops,
            travel_requests=travel_requests
        )

        # The list of bus_stops of a bus_line might contain the same bus_stop_osm_ids more than once.
        # For this reason, each travel_request needs to be related with the correct index in the bus_stops list.
        # So, the values 'starting_timetable_entry_index' and 'ending_timetable_entry_index' are estimated.
        #
        correspond_travel_requests_to_bus_stops(
            travel_requests=timetable_generator.travel_requests,
            bus_stops=timetable_generator.bus_stops
        )

        # 4: Based on the response of the Route Generator, which includes details about the followed bus_route,
        #    and using only one bus vehicle, the Look Ahead generates some initial timetables which cover the
        #    whole datetime period from timetables_starting_datetime to timetables_ending_datetime.
        #    Initially, the list of travel requests of these timetables is empty, and the departure_datetime and
        #    arrival_datetime values of the timetable_entries are based exclusively on the details of the bus_route.
        #    In the next steps of the algorithm, these timetables are used in the initial clustering
        #    of the travel requests.
        #
        timetable_generator.timetables = generate_initial_timetables(
            bus_line_id=bus_line_id,
            timetables_starting_datetime=timetables_starting_datetime,
            timetables_ending_datetime=timetables_ending_datetime,
            route_generator_response=timetable_generator.route_generator_response
        )

        current_average_waiting_time_of_timetables = float('Inf')

        while True:
            new_timetables = generate_new_timetables_based_on_travel_requests(
                current_timetables=timetable_generator.timetables,
                travel_requests=timetable_generator.travel_requests
            )
            new_average_waiting_time_of_timetables = calculate_average_waiting_time_of_timetables_in_seconds(
                timetables=new_timetables
            )
            if new_average_waiting_time_of_timetables < current_average_waiting_time_of_timetables:
                timetable_generator.timetables = new_timetables
                current_average_waiting_time_of_timetables = new_average_waiting_time_of_timetables
                print_timetables(timetables=timetable_generator.timetables)
            else:
                break

        print_timetables(timetables=timetable_generator.timetables)

        self.mongodb_database_connection.delete_timetable_documents(
            bus_line_id=bus_line.get('bus_line_id')
        )
        self.mongodb_database_connection.insert_timetable_documents(
            timetable_documents=timetable_generator.timetables
        )
        log(module_name='look_ahead_handler', log_type='DEBUG',
            log_message='insert_timetable_documents (mongodb_database): ok')

    def generate_timetables_for_bus_lines(self, timetables_starting_datetime, timetables_ending_datetime,
                                          requests_min_departure_datetime, requests_max_departure_datetime):
        """
        Generate timetables for all bus_lines, for a selected datetime period,
        evaluating travel_requests of a specific datetime period.

        :param timetables_starting_datetime: datetime
        :param timetables_ending_datetime: datetime
        :param requests_min_departure_datetime: datetime
        :param requests_max_departure_datetime: datetime
        :return: None
        """
        bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.generate_timetables_for_bus_line(
                bus_line=bus_line,
                timetables_starting_datetime=timetables_starting_datetime,
                timetables_ending_datetime=timetables_ending_datetime,
                requests_min_departure_datetime=requests_min_departure_datetime,
                requests_max_departure_datetime=requests_max_departure_datetime
            )

    def update_timetables_of_bus_line(self, bus_line=None, bus_line_id=None):
        """
        Update the timetables of a bus_line, taking into consideration the current levels of traffic_density.

        :param bus_line: bus_line_document
        :param bus_line_id: int
        :return: None
        """
        if bus_line is None and bus_line_id is None:
            return None
        elif bus_line is None:
            bus_line = self.mongodb_database_connection.find_bus_line_document(bus_line_id=bus_line_id)
        else:
            bus_line_id = bus_line.get('bus_line_id')

        bus_stops = bus_line.get('bus_stops')
        timetables = self.mongodb_database_connection.find_timetable_documents(bus_line_ids=[bus_line_id])
        travel_requests = get_travel_requests_of_timetables(timetables=timetables)

        timetable_updater = TimetableUpdater(
            bus_stops=bus_stops,
            timetables=timetables,
            travel_requests=travel_requests
        )
        update_entries_of_timetables(
            timetables=timetable_updater.timetables,
            route_generator_response=timetable_updater.route_generator_response
        )
        current_average_waiting_time_of_timetables = calculate_average_waiting_time_of_timetables_in_seconds(
            timetables=timetable_updater.timetables
        )
        print_timetables(timetables=timetable_updater.timetables)

        while True:
            new_timetables = generate_new_timetables_based_on_travel_requests(
                current_timetables=timetable_updater.timetables,
                travel_requests=timetable_updater.travel_requests
            )
            new_average_waiting_time_of_timetables = calculate_average_waiting_time_of_timetables_in_seconds(
                timetables=new_timetables
            )
            if new_average_waiting_time_of_timetables < current_average_waiting_time_of_timetables:
                timetable_updater.timetables = new_timetables
                current_average_waiting_time_of_timetables = new_average_waiting_time_of_timetables
                print_timetables(timetables=timetable_updater.timetables)
            else:
                break

        print_timetables(timetables=timetable_updater.timetables)

        self.mongodb_database_connection.delete_timetable_documents(
            bus_line_id=bus_line.get('bus_line_id')
        )
        self.mongodb_database_connection.insert_timetable_documents(
            timetable_documents=timetable_updater.timetables
        )
        log(module_name='look_ahead_handler', log_type='DEBUG',
            log_message='update_timetable_documents (mongodb_database): ok')

    def update_timetables_of_bus_lines(self):
        """
        Update the timetables of all bus_lines, taking into consideration the current levels of traffic_density.

        :return: None
        """
        bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.update_timetables_of_bus_line(bus_line=bus_line)
コード例 #2
0
class TrafficDataSimulator(object):
    def __init__(self):
        self.mongodb_database_connection = MongodbDatabaseConnection(host=mongodb_host, port=mongodb_port)
        log(module_name='traffic_data_simulator', log_type='DEBUG',
            log_message='mongodb_database_connection: established')

    def clear_traffic_density(self):
        self.mongodb_database_connection.clear_traffic_density()

    def generate_traffic_data_between_two_bus_stops(self, starting_bus_stop=None, ending_bus_stop=None,
                                                    starting_bus_stop_name=None, ending_bus_stop_name=None):
        """
        Generate random traffic density values for the edges which connect two bus_stops.

        bus_stop_document: {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}}

        bus_stop_waypoints_document: {
            '_id', 'starting_bus_stop': {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}},
            'ending_bus_stop': {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}},
            'waypoints': [[edge_object_id]]
        }
        :param starting_bus_stop: bus_stop_document
        :param ending_bus_stop: bus_stop_document
        :param starting_bus_stop_name: string
        :param ending_bus_stop_name: string
        :return: None
        """
        bus_stop_waypoints_document = self.mongodb_database_connection.find_bus_stop_waypoints_document(
            starting_bus_stop=starting_bus_stop,
            ending_bus_stop=ending_bus_stop,
            starting_bus_stop_name=starting_bus_stop_name,
            ending_bus_stop_name=ending_bus_stop_name
        )
        edge_object_ids_included_in_bus_stop_waypoints_document = \
            self.mongodb_database_connection.get_edge_object_ids_included_in_bus_stop_waypoints(
                bus_stop_waypoints=bus_stop_waypoints_document
            )
        self.generate_traffic_data_for_edge_object_ids(
            edge_object_ids=edge_object_ids_included_in_bus_stop_waypoints_document
        )

    def generate_traffic_data_between_multiple_bus_stops(self, bus_stops=None, bus_stop_names=None):
        """
        Generate random traffic density values for the edges which connect multiple bus_stops.

        bus_stop_document: {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}}

        :param bus_stops: [bus_stop_documents]
        :param bus_stop_names: [string]
        :return: None
        """
        if bus_stops is not None:
            number_of_bus_stops = len(bus_stops)

            for i in range(0, number_of_bus_stops - 1):
                starting_bus_stop = bus_stops[i]
                ending_bus_stop = bus_stops[i + 1]
                self.generate_traffic_data_between_two_bus_stops(
                    starting_bus_stop=starting_bus_stop,
                    ending_bus_stop=ending_bus_stop
                )

        elif bus_stop_names is not None:
            number_of_bus_stop_names = len(bus_stop_names)

            for i in range(0, number_of_bus_stop_names - 1):
                starting_bus_stop_name = bus_stop_names[i]
                ending_bus_stop_name = bus_stop_names[i + 1]
                self.generate_traffic_data_between_two_bus_stops(
                    starting_bus_stop_name=starting_bus_stop_name,
                    ending_bus_stop_name=ending_bus_stop_name
                )

        else:
            pass

    def generate_traffic_data_for_bus_line(self, bus_line=None, line_id=None):
        """
        Generate random traffic density values for the edge_documents which are included in a bus_line_document.

        bus_line_document: {
            '_id', 'line_id', 'bus_stops': [{'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}}]
        }
        :param bus_line: bus_line_document
        :param line_id: int
        :return: None
        """
        edge_object_ids_included_in_bus_line_document = \
            self.mongodb_database_connection.get_edge_object_ids_included_in_bus_line(
                bus_line=bus_line,
                line_id=line_id
            )

        self.generate_traffic_data_for_edge_object_ids(
            edge_object_ids=edge_object_ids_included_in_bus_line_document
        )

    def generate_traffic_data_for_bus_lines(self, bus_lines=None):
        """
        Generate random traffic density values for the edge_documents which are included in a bus_line_documents.

        bus_line_document: {
            '_id', 'line_id', 'bus_stops': [{'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}}]
        }
        :param bus_lines: [bus_line_document]
        :return: None
        """
        if bus_lines is None:
            bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.generate_traffic_data_for_bus_line(bus_line=bus_line)

    def generate_traffic_data_for_edge_object_ids(self, edge_object_ids):
        """
        Generate random traffic density values and update the corresponding edge_documents.

        edge_document: {
            '_id', 'starting_node': {'osm_id', 'point': {'longitude', 'latitude'}},
            'ending_node': {'osm_id', 'point': {'longitude', 'latitude'}},
            'max_speed', 'road_type', 'way_id', 'traffic_density'
        }
        :param edge_object_ids: [ObjectId]
        :return: None
        """
        number_of_edge_object_ids = len(edge_object_ids)
        number_of_produced_traffic_values = random.randint(0, number_of_edge_object_ids - 1)

        for i in range(0, number_of_produced_traffic_values):
            edge_object_ids_index = random.randint(0, number_of_edge_object_ids - 1)
            edge_object_id = edge_object_ids[edge_object_ids_index]
            new_traffic_density_value = random.uniform(0, 1)
            self.mongodb_database_connection.update_traffic_density(
                edge_object_id=edge_object_id,
                new_traffic_density_value=new_traffic_density_value
            )
コード例 #3
0
class LookAheadHandler(object):
    def __init__(self):
        self.mongodb_database_connection = MongodbDatabaseConnection(
            host=mongodb_host, port=mongodb_port)
        log(module_name='look_ahead_handler',
            log_type='DEBUG',
            log_message='mongodb_database_connection: established')

    def generate_bus_line(self, bus_stop_names, bus_line_id=None):
        """
        Generate a bus_line, consisted of a bus_line_id and a list of bus_stops, and store it to the corresponding
        collection of the System Database. Moreover, identify all the possible waypoints between the bus_stops
        of the bus_line, and populate the BusStopWaypoints collection.

        :param bus_stop_names: [string]
        :param bus_line_id: int
        :return: None
        """
        # 1: The inputs: bus_line_id and bus_stop_names are provided to the function, so as as a bus_line
        #    with the corresponding bus_line_id and bus_stops to be generated.
        #
        # 2: The Look Ahead connects to the System Database and retrieves the bus_stops which correspond to
        #    the provided bus_stop_names. The function returns None and the bus_line is not generated,
        #    in case there is a bus_stop_name which does not correspond to a stored bus_stop.
        #
        if bus_line_id is None:
            maximum_bus_line_id = self.mongodb_database_connection.get_maximum_or_minimum(
                collection='bus_line')
            bus_line_id = maximum_bus_line_id + 1

        bus_stops = []

        for bus_stop_name in bus_stop_names:
            bus_stop_document = self.mongodb_database_connection.find_bus_stop_document(
                name=bus_stop_name)

            if bus_stop_document is None:
                log_message = 'find_bus_stop_document (mongodb_database) - name:', bus_stop_name, '- result: None'
                log(module_name='look_ahead_handler',
                    log_type='DEBUG',
                    log_message=log_message)
                return None
            else:
                bus_stops.append(bus_stop_document)

        # 3: The intermediate waypoints of the bus_routes, which are generated while combining starting and
        #    ending bus_stops of the bus_line, should be stored as bus_stop_waypoints_documents at the System Database.
        #    The Look Ahead checks the existing bus_stop_waypoints_documents and communicates with the Route Generator
        #    in order to identify the waypoints of the bus_routes which are not already stored. The newly generated
        #    bus_stop_waypoints_documents are getting stored to the corresponding collection of the System Database.
        #    The function returns None and the bus_line is not generated, in case the Route Generator can not identify
        #    a possible route in order to connect the bus_stops of the bus_line.
        #
        number_of_bus_stops = len(bus_stops)

        for i in range(0, number_of_bus_stops - 1):
            starting_bus_stop = bus_stops[i]
            ending_bus_stop = bus_stops[i + 1]

            bus_stop_waypoints_document = self.mongodb_database_connection.find_bus_stop_waypoints_document(
                starting_bus_stop=starting_bus_stop,
                ending_bus_stop=ending_bus_stop)
            if bus_stop_waypoints_document is None:
                route_generator_response = get_waypoints_between_two_bus_stops(
                    starting_bus_stop=starting_bus_stop,
                    ending_bus_stop=ending_bus_stop)
                if route_generator_response is None:
                    log(module_name='look_ahead_handler',
                        log_type='DEBUG',
                        log_message=
                        'get_waypoints_between_two_bus_stops (route_generator): None'
                        )
                    return None
                else:
                    waypoints = route_generator_response.get('waypoints')

                    if len(waypoints) == 0:
                        log(module_name='look_ahead_handler',
                            log_type='DEBUG',
                            log_message=
                            'get_waypoints_between_two_bus_stops (route_generator): None'
                            )
                        return None

                    lists_of_edge_object_ids = []

                    for list_of_edges in waypoints:
                        list_of_edge_object_ids = []

                        for edge in list_of_edges:
                            edge_object_id = edge.get('_id')
                            list_of_edge_object_ids.append(edge_object_id)

                        lists_of_edge_object_ids.append(
                            list_of_edge_object_ids)

                    # waypoints: [[edge_object_id]]
                    #
                    waypoints = lists_of_edge_object_ids

                    self.mongodb_database_connection.insert_bus_stop_waypoints_document(
                        starting_bus_stop=starting_bus_stop,
                        ending_bus_stop=ending_bus_stop,
                        waypoints=waypoints)

        # 4: The Look Ahead stores the newly generated bus_line_document, which is consisted of the bus_line_id
        #    and the list of bus_stops, to the corresponding collection of the System Database.
        #    In case there is an already existing bus_line_document, with the same bus_line_id,
        #    then the list of bus_stops gets updated.
        #
        bus_line_document = {
            'bus_line_id': bus_line_id,
            'bus_stops': bus_stops
        }
        self.mongodb_database_connection.insert_bus_line_document(
            bus_line_document=bus_line_document)

        log(module_name='look_ahead_handler',
            log_type='DEBUG',
            log_message='insert_bus_line_document (mongodb_database): ok')

    def generate_timetables_for_bus_line(self,
                                         timetables_starting_datetime,
                                         timetables_ending_datetime,
                                         requests_min_departure_datetime,
                                         requests_max_departure_datetime,
                                         bus_line=None,
                                         bus_line_id=None):
        """
        Generate timetables for a bus_line, for a selected datetime period,
        evaluating travel_requests of a specific datetime period.

        - The input: timetables_starting_datetime and input: timetables_ending_datetime
          are provided to the function, so as timetables for the specific datetime period
          to be generated.

        - The input: requests_min_departure_datetime and input: requests_max_departure_datetime
          are provided to the function, so as travel_requests with departure_datetime corresponding
          to the the specific datetime period to be evaluated.

        - The input: bus_line or input: bus_line_id is provided to the function,
          so as timetables for the specific bus_line to be generated.

        :param timetables_starting_datetime: datetime
        :param timetables_ending_datetime: datetime
        :param requests_min_departure_datetime: datetime
        :param requests_max_departure_datetime: datetime
        :param bus_line: bus_line_document
        :param bus_line_id: int
        :return: None
        """

        maximum_timetable_id_in_database = self.mongodb_database_connection.get_maximum_or_minimum(
            collection='timetable')

        # 1: The list of bus_stops corresponding to the provided bus_line is retrieved.
        #
        # bus_stop_document: {
        #     '_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}
        # }
        # bus_stops: [bus_stop_document]
        #
        if bus_line is None and bus_line_id is None:
            return None
        elif bus_line is None:
            bus_line = self.mongodb_database_connection.find_bus_line_document(
                bus_line_id=bus_line_id)
        else:
            bus_line_id = bus_line.get('bus_line_id')

        bus_stops = bus_line.get('bus_stops')

        # 2: The Look Ahead retrieves from the System Database the travel_requests with
        #    departure_datetime higher than requests_min_departure_datetime and
        #    lower than requests_max_departure_datetime.
        #
        # travel_request_document: {
        #     '_id', 'client_id', 'bus_line_id',
        #     'starting_bus_stop': {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}},
        #     'ending_bus_stop': {'_id', 'osm_id', 'name', 'point': {'longitude', 'latitude'}},
        #     'departure_datetime', 'arrival_datetime'
        # }
        # travel_requests: [travel_request_document]
        #
        travel_requests = self.mongodb_database_connection.find_travel_request_documents(
            bus_line_ids=[bus_line_id],
            min_departure_datetime=requests_min_departure_datetime,
            max_departure_datetime=requests_max_departure_datetime)

        # 3: (TimetableGenerator is initialized) The Look Ahead sends a request to the Route Generator so as
        #    to identify the less time-consuming bus_route between the bus_stops of bus_line,
        #    while taking into consideration the current levels of traffic density.
        #
        timetable_generator = TimetableGenerator(
            maximum_timetable_id_in_database=maximum_timetable_id_in_database,
            bus_line_id=bus_line_id,
            bus_stops=bus_stops,
            travel_requests=travel_requests)

        # The list of bus_stops of a bus_line might contain the same bus_stop_osm_ids more than once.
        # For this reason, each travel_request needs to be related with the correct index in the bus_stops list.
        # So, the values 'starting_timetable_entry_index' and 'ending_timetable_entry_index' are estimated.
        #
        correspond_travel_requests_to_bus_stops(
            travel_requests=timetable_generator.travel_requests,
            bus_stops=timetable_generator.bus_stops)

        # 4: Based on the response of the Route Generator, which includes details about the followed bus_route,
        #    and using only one bus vehicle, the Look Ahead generates some initial timetables which cover the
        #    whole datetime period from timetables_starting_datetime to timetables_ending_datetime.
        #    Initially, the list of travel requests of these timetables is empty, and the departure_datetime and
        #    arrival_datetime values of the timetable_entries are based exclusively on the details of the bus_route.
        #    In the next steps of the algorithm, these timetables are used in the initial clustering
        #    of the travel requests.
        #
        timetable_generator.timetables = generate_initial_timetables(
            bus_line_id=bus_line_id,
            timetables_starting_datetime=timetables_starting_datetime,
            timetables_ending_datetime=timetables_ending_datetime,
            route_generator_response=timetable_generator.
            route_generator_response)

        current_average_waiting_time_of_timetables = float('Inf')

        while True:
            new_timetables = generate_new_timetables_based_on_travel_requests(
                current_timetables=timetable_generator.timetables,
                travel_requests=timetable_generator.travel_requests)
            new_average_waiting_time_of_timetables = calculate_average_waiting_time_of_timetables_in_seconds(
                timetables=new_timetables)
            if new_average_waiting_time_of_timetables < current_average_waiting_time_of_timetables:
                timetable_generator.timetables = new_timetables
                current_average_waiting_time_of_timetables = new_average_waiting_time_of_timetables
                print_timetables(timetables=timetable_generator.timetables)
            else:
                break

        print_timetables(timetables=timetable_generator.timetables)

        self.mongodb_database_connection.delete_timetable_documents(
            bus_line_id=bus_line.get('bus_line_id'))
        self.mongodb_database_connection.insert_timetable_documents(
            timetable_documents=timetable_generator.timetables)
        log(module_name='look_ahead_handler',
            log_type='DEBUG',
            log_message='insert_timetable_documents (mongodb_database): ok')

    def generate_timetables_for_bus_lines(self, timetables_starting_datetime,
                                          timetables_ending_datetime,
                                          requests_min_departure_datetime,
                                          requests_max_departure_datetime):
        """
        Generate timetables for all bus_lines, for a selected datetime period,
        evaluating travel_requests of a specific datetime period.

        :param timetables_starting_datetime: datetime
        :param timetables_ending_datetime: datetime
        :param requests_min_departure_datetime: datetime
        :param requests_max_departure_datetime: datetime
        :return: None
        """
        bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.generate_timetables_for_bus_line(
                bus_line=bus_line,
                timetables_starting_datetime=timetables_starting_datetime,
                timetables_ending_datetime=timetables_ending_datetime,
                requests_min_departure_datetime=requests_min_departure_datetime,
                requests_max_departure_datetime=requests_max_departure_datetime
            )

    def update_timetables_of_bus_line(self, bus_line=None, bus_line_id=None):
        """
        Update the timetables of a bus_line, taking into consideration the current levels of traffic_density.

        :param bus_line: bus_line_document
        :param bus_line_id: int
        :return: None
        """
        if bus_line is None and bus_line_id is None:
            return None
        elif bus_line is None:
            bus_line = self.mongodb_database_connection.find_bus_line_document(
                bus_line_id=bus_line_id)
        else:
            bus_line_id = bus_line.get('bus_line_id')

        bus_stops = bus_line.get('bus_stops')
        timetables = self.mongodb_database_connection.find_timetable_documents(
            bus_line_ids=[bus_line_id])
        travel_requests = get_travel_requests_of_timetables(
            timetables=timetables)

        timetable_updater = TimetableUpdater(bus_stops=bus_stops,
                                             timetables=timetables,
                                             travel_requests=travel_requests)
        update_entries_of_timetables(
            timetables=timetable_updater.timetables,
            route_generator_response=timetable_updater.route_generator_response
        )
        current_average_waiting_time_of_timetables = calculate_average_waiting_time_of_timetables_in_seconds(
            timetables=timetable_updater.timetables)
        print_timetables(timetables=timetable_updater.timetables)

        while True:
            new_timetables = generate_new_timetables_based_on_travel_requests(
                current_timetables=timetable_updater.timetables,
                travel_requests=timetable_updater.travel_requests)
            new_average_waiting_time_of_timetables = calculate_average_waiting_time_of_timetables_in_seconds(
                timetables=new_timetables)
            if new_average_waiting_time_of_timetables < current_average_waiting_time_of_timetables:
                timetable_updater.timetables = new_timetables
                current_average_waiting_time_of_timetables = new_average_waiting_time_of_timetables
                print_timetables(timetables=timetable_updater.timetables)
            else:
                break

        print_timetables(timetables=timetable_updater.timetables)

        self.mongodb_database_connection.delete_timetable_documents(
            bus_line_id=bus_line.get('bus_line_id'))
        self.mongodb_database_connection.insert_timetable_documents(
            timetable_documents=timetable_updater.timetables)
        log(module_name='look_ahead_handler',
            log_type='DEBUG',
            log_message='update_timetable_documents (mongodb_database): ok')

    def update_timetables_of_bus_lines(self):
        """
        Update the timetables of all bus_lines, taking into consideration the current levels of traffic_density.

        :return: None
        """
        bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.update_timetables_of_bus_line(bus_line=bus_line)
コード例 #4
0
class TrafficDataSimulator(object):
    def __init__(self):
        self.mongodb_database_connection = MongodbDatabaseConnection(host=mongodb_host, port=mongodb_port)
        self.lowest_traffic_density_value = 0
        self.highest_traffic_density_value = 1
        log(module_name='traffic_data_simulator', log_type='DEBUG',
            log_message='mongodb_database_connection: established')

    def clear_traffic_density(self):
        self.mongodb_database_connection.clear_traffic_density()

    def generate_traffic_data_between_two_bus_stops(self, starting_bus_stop=None, ending_bus_stop=None,
                                                    starting_bus_stop_name=None, ending_bus_stop_name=None):
        """
        Generate random traffic density values for the edges which connect two bus_stops.

        :param starting_bus_stop: bus_stop_document
        :param ending_bus_stop: bus_stop_document
        :param starting_bus_stop_name: string
        :param ending_bus_stop_name: string
        :return: None
        """
        bus_stop_waypoints_document = self.mongodb_database_connection.find_bus_stop_waypoints_document(
            starting_bus_stop=starting_bus_stop,
            ending_bus_stop=ending_bus_stop,
            starting_bus_stop_name=starting_bus_stop_name,
            ending_bus_stop_name=ending_bus_stop_name
        )
        edge_object_ids_included_in_bus_stop_waypoints_document = \
            self.mongodb_database_connection.get_edge_object_ids_included_in_bus_stop_waypoints(
                bus_stop_waypoints=bus_stop_waypoints_document
            )
        self.generate_traffic_data_for_edge_object_ids(
            edge_object_ids=edge_object_ids_included_in_bus_stop_waypoints_document
        )

    def generate_traffic_data_between_multiple_bus_stops(self, bus_stops=None, bus_stop_names=None):
        """
        Generate random traffic density values for the edges which connect multiple bus_stops.

        :param bus_stops: [bus_stop_documents]
        :param bus_stop_names: [string]
        :return: None
        """
        if bus_stops is not None:
            number_of_bus_stops = len(bus_stops)

            for i in range(0, number_of_bus_stops - 1):
                starting_bus_stop = bus_stops[i]
                ending_bus_stop = bus_stops[i + 1]
                self.generate_traffic_data_between_two_bus_stops(
                    starting_bus_stop=starting_bus_stop,
                    ending_bus_stop=ending_bus_stop
                )

        elif bus_stop_names is not None:
            number_of_bus_stop_names = len(bus_stop_names)

            for i in range(0, number_of_bus_stop_names - 1):
                starting_bus_stop_name = bus_stop_names[i]
                ending_bus_stop_name = bus_stop_names[i + 1]
                self.generate_traffic_data_between_two_bus_stops(
                    starting_bus_stop_name=starting_bus_stop_name,
                    ending_bus_stop_name=ending_bus_stop_name
                )

        else:
            pass

    def generate_traffic_data_for_bus_line(self, bus_line=None, bus_line_id=None):
        """
        Generate random traffic density values for the edge_documents which are included in a bus_line_document.

        :param bus_line: bus_line_document
        :param bus_line_id: int
        :return: None
        """
        edge_object_ids_included_in_bus_line_document = \
            self.mongodb_database_connection.get_edge_object_ids_included_in_bus_line(
                bus_line=bus_line,
                bus_line_id=bus_line_id
            )

        self.generate_traffic_data_for_edge_object_ids(
            edge_object_ids=edge_object_ids_included_in_bus_line_document
        )

    def generate_traffic_data_for_bus_lines(self, bus_lines=None):
        """
        Generate random traffic density values for the edge_documents which are included in a bus_line_documents.

        :param bus_lines: [bus_line_document]
        :return: None
        """
        if bus_lines is None:
            bus_lines = self.mongodb_database_connection.find_bus_line_documents()

        for bus_line in bus_lines:
            self.generate_traffic_data_for_bus_line(bus_line=bus_line)

    def generate_traffic_data_for_edge_object_ids(self, edge_object_ids):
        """
        Generate random traffic density values and update the corresponding edge_documents.

        :param edge_object_ids: [ObjectId]
        :return: None
        """
        number_of_edge_object_ids = len(edge_object_ids)
        number_of_produced_traffic_values = random.randint(0, number_of_edge_object_ids - 1)

        for i in range(0, number_of_produced_traffic_values):
            # edge_object_ids_index = random.randint(0, number_of_edge_object_ids - 1)
            edge_object_ids_index = i
            edge_object_id = edge_object_ids[edge_object_ids_index]
            new_traffic_density_value = random.uniform(
                self.lowest_traffic_density_value,
                self.highest_traffic_density_value
            )
            self.mongodb_database_connection.update_traffic_density(
                edge_object_id=edge_object_id,
                new_traffic_density_value=new_traffic_density_value
            )

    def set_traffic_density_limits(self, lowest_traffic_density_value, highest_traffic_density_value):
        """
        Set the lowest and highest traffic density values.

        :param lowest_traffic_density_value: float: [0, 1]
        :param highest_traffic_density_value: float: [0, 1]
        :return: None
        """
        self.lowest_traffic_density_value = lowest_traffic_density_value
        self.highest_traffic_density_value = highest_traffic_density_value