Пример #1
0
 def __init__(self, graph, starting_vertex_id=1, reset_heuristic=False):
     self.route = Route(graph)
     self.starting_vertex_id = starting_vertex_id
     self.route.goto(
         self.route.graph.get_vertex_by_id(starting_vertex_id))
     self.done = False
     self.attempted_starting_vertex_ids = list([starting_vertex_id])
     self.remaining_starting_vertex_ids = self.get_remaining_starting_vertex_ids(
     )
     self.reset_heuristic = reset_heuristic
     self.crosses = 0
Пример #2
0
            def crossover(self, other_chromosome, every_other=True):
                new_path = list([])

                if every_other:  # Combines chromosome by alternating allels.
                    self_index = 0
                    other_index = 1
                    my_turn = True

                    while len(new_path) < len(self.route.vertices) - 1:
                        if my_turn and self_index < len(
                                self.route.vertices) - 1:
                            if self.route.vertices[
                                    self_index].vertex_id not in new_path:
                                new_path.append(
                                    self.route.vertices[self_index].vertex_id)
                                my_turn = False
                            self_index += 1
                        else:
                            if other_chromosome.route.vertices[
                                    other_index].vertex_id not in new_path:
                                new_path.append(
                                    other_chromosome.route.
                                    vertices[other_index].vertex_id)
                                my_turn = True
                            if other_index >= len(
                                    other_chromosome.route.vertices) - 2:
                                my_turn = True
                            else:
                                other_index += 1
                else:  # Splits the two chromosomes down the middle
                    index = 0

                    while len(new_path) < len(self.route.vertices) - 1:
                        if index < len(self.route.vertices) // 2:
                            if self.route.vertices[
                                    index].vertex_id not in new_path:
                                new_path.append(
                                    self.route.vertices[index].vertex_id)
                                index += 1
                        else:
                            remaining_vertices = [
                                vertex for vertex in self.route.vertices
                                if vertex.vertex_id not in new_path
                            ]
                            for remainining_vertex in remaining_vertices:
                                new_path.append(remainining_vertex.vertex_id)

                new_route = Route(self.route.graph)
                new_route.walk_complete_path(new_path)

                resultant_chromosome = TravelingSalesman.GeneticAlgorithm.Chromosome(
                    None, new_route)

                return resultant_chromosome
Пример #3
0
        def initialize_population(self):
            city_range = list(range(1, 1 + len(self.graph.vertices)))

            for chromosome_index in range(self.population_size):
                random_city_order = deepcopy(city_range)
                random.shuffle(random_city_order)
                random_route = Route(graph)
                random_route.walk_complete_path(random_city_order)
                chromosome = TravelingSalesman.GeneticAlgorithm.Chromosome(
                    chromosome_index, random_route)
                self.population.append(chromosome)

            self.population = np.array(self.population)
Пример #4
0
    def depth_first_search(graph, source_vertex_id=1, target_vertex_id=11):
        dfs_stack = DepthFirstSearchStack()

        def search_deeper(current_vertex, current_route):
            # Get unfinished remaining adjacent vertices
            remaining_adjacent_vertices = dfs_stack.get_unfinished_adjacent_vertices(
                current_vertex.adjacent_vertices)
            # Update the route with the new vertex
            current_route.goto(current_vertex.vertex_id)
            # Push the current vertex ontop of the dfs stack
            dfs_stack.push(current_vertex, current_route)

            # If there are no remaining adjacent vertices
            if len(remaining_adjacent_vertices) == 0:
                # Pop the finished node off the stack
                finished_node = dfs_stack.pop()
                # walk back from the route since no longer part of it
                current_route.walk_back()
                # Mark the node complete. Update lists.
                dfs_stack.node_complete(finished_node)

                # If there are still items on the stack.
                if len(dfs_stack.node_stack) > 0:
                    # Search deeper using the previous item as guide.
                    search_deeper(dfs_stack.node_stack[-1].vertex,
                                  current_route)
            else:
                # Search the first adjacent vertex
                search_deeper(remaining_adjacent_vertices[0], current_route)

        source_vertex = graph.get_vertex_by_id(source_vertex_id)
        route = Route([], graph)
        search_deeper(source_vertex, route)
        return dfs_stack.get_path_to_finished_vertex_id(target_vertex_id)
Пример #5
0
    def initialize_population(self):
        city_range = list(range(1, 1 + len(self.graph.vertices)))

        for chromosome_index in range(self.population_size):
            random_city_order = deepcopy(city_range, memo={})
            random.shuffle(random_city_order)
            random_route = Route(self.graph)
            random_route.walk_complete_path(random_city_order)
            chromosome = GeneticAlgorithm.Chromosome(
                chromosome_index,
                random_route,
                crossover_method=self.crossover_method,
                mutation_method=self.mutation_method)
            self.population.append(chromosome)

        self.population = np.array(self.population)
Пример #6
0
    def breadth_first_search(graph, source_vertex_id=1, target_vertex_id=11):
        bfs_tree = BreadthFirstSearchTree()

        current_vertex = graph.get_vertex_by_id(source_vertex_id)
        route = Route([current_vertex.vertex_id], graph)
        current_layer = 0
        current_node = BreadthFirstSearchTree.Node("source", current_vertex,
                                                   str(current_layer), route)
        node_index = 1
        bfs_tree.add_node(current_node)

        # Iterate over each layer in the bfs tree and create the next layer
        while str(current_layer) in bfs_tree.nodes.keys():
            # Iterate over all nodes
            for node in bfs_tree.nodes[str(current_layer)]:
                # Loop over its adjacent vertices
                for adjacent_vertex in node.vertex.adjacent_vertices:
                    # Copy the route of the current node
                    current_route = deepcopy(node.minimum_route)

                    # Update the current route with the new vertex goto
                    current_route.goto(adjacent_vertex.vertex_id)

                    # Create a node representation of the vertex/route
                    adjacent_node = BreadthFirstSearchTree.Node(
                        str(node_index), adjacent_vertex,
                        str(current_layer + 1), current_route)

                    # Try to add the node
                    if bfs_tree.add_node(adjacent_node) is True:
                        # If added, append the node and increment the node_index
                        node.adjacent_nodes.append(adjacent_node)
                        node_index += 1

                    print("=== DISPLAYING UPDATED TREE === ")
                    bfs_tree.display()

            # Iterate to the next layer to be done
            current_layer += 1

        # Iterate over the final bfs_tree looking for the target_vertex_id
        for current_layer in bfs_tree.nodes.keys():
            for node in bfs_tree.nodes[current_layer]:
                if node.vertex.vertex_id == target_vertex_id:
                    # Adjust indices within minimum_route to match initial representation
                    for vertex_id in node.minimum_route.vertex_order:
                        vertex_id += 1
                    # Return minimum route.
                    return node.minimum_route
Пример #7
0
 def __init__(self, graph):
     self.graph = graph
     self.edge_dictionary = {}
     self.route = Route(graph)
     self.max_edge_count = 0
Пример #8
0
class CrowdSolution(object):
    def __init__(self, graph):
        self.graph = graph
        self.edge_dictionary = {}
        self.route = Route(graph)
        self.max_edge_count = 0

    def log(self, log_path):
        log = open(log_path, "w+")
        log.write("edge_key" + ", " + "edge_count" + "\n")

        for edge_key, edge_entry in self.edge_dictionary.items():
            log.write(str(edge_entry.edge_key) + ", " + str(edge_entry.edge_count) + "\n")

        log.close()

    def add_edge_entry(self, new_edge_entry):
        ## EDGE CANNOT BE REMOVED HERE. NEEDS TO BE CONSERVATIVE
        ## ISSUE
        spot_taken = False
        keys_to_be_deleted = list([])

        self.display()
        for edge_key, edge_entry in self.edge_dictionary.items():
            if edge_entry.edge.vertices[0].vertex_id == new_edge_entry.edge.vertices[0].vertex_id or edge_entry.edge.vertices[0].vertex_id == new_edge_entry.edge.vertices[0].vertex_id:
                if new_edge_entry.edge_count >= edge_entry.edge.distance:
                    # Entries have same starting vertex
                    if new_edge_entry.edge.distance <= edge_entry.edge.distance:
                        keys_to_be_deleted.append(edge_entry.edge_key)
                        break
                    else:
                        spot_taken = True
                else:
                    spot_taken = True

        for key in keys_to_be_deleted:
            del self.edge_dictionary[key]

        if not spot_taken:
            self.edge_dictionary[new_edge_entry.edge_key] = new_edge_entry


    def load(self, log_path):
        with open(log_path, "r") as log:
            data_line = log.readline()

            while True:
                data_line = log.readline()
                if len(data_line) == 0:
                    break

                edge_key, edge_count = data_line.split(", ")
                edge_count = int(edge_count)
                if edge_count > self.max_edge_count:
                    self.max_edge_count = edge_count
                vertices = re.findall(r'\d+', edge_key)
                vertex_start = self.graph.get_vertex_by_id(int(vertices[0]))
                vertex_end = self.graph.get_vertex_by_id(int(vertices[1]))
                edge_entry = CrowdSolution.EdgeEntry(edge_key=edge_key, edge_count=edge_count, edge=Edge(vertex_start, vertex_end))
                self.edge_dictionary[edge_entry.edge_key] = edge_entry

#        self.display()

    def display(self):
        for edge_key, edge_entry in self.edge_dictionary.items():
            print(str(edge_entry.edge_key) + ", " + str(edge_entry.edge_count))

    def generate_heat_map(self, superiority_tolerance=0.8):
        graph = self.graph
        x = list([])
        y = list([])
        plots = list([])
        arrow_plots = list([])
        arrow_labels = list([])

        # Iterate over vertices, retrieving x and y coordinates
        for vertex in graph.vertices:
            x.append(vertex.x)
            y.append(vertex.y)

        # Plot the vertices
        vertex_plot = plt.scatter(x, y, label="Vertices")
        plots.append(vertex_plot)

        for edge_key, edge_entry in self.edge_dictionary.items():
            if edge_entry.edge_count >= (self.max_edge_count * superiority_tolerance):
                vertices = re.findall(r'\d+', edge_entry.edge_key)
                vertex_start = graph.get_vertex_by_id(int(vertices[0]))
                vertex_end = graph.get_vertex_by_id(int(vertices[1]))
                arrow_label = "Edge {}->{}".format(vertices[0], vertices[1])
                arrow_plot = plt.arrow(vertex_start.x, vertex_start.y, vertex_end.x-vertex_start.x, vertex_end.y-vertex_start.y,
                                       head_width=1, head_length=1,
                                       color='#{}{}{}'.format(Math.normalize_rgb(self.max_edge_count - edge_entry.edge_count, 0, self.max_edge_count),
                                                              "00",
                                                              Math.normalize_rgb(edge_entry.edge_count, 0, self.max_edge_count)),
                                       label=arrow_label)
                plots.append(arrow_plot)
                arrow_plots.append(arrow_plot)
                arrow_labels.append(arrow_label)

        # Show the graph with a legend
        plt.legend(arrow_plots, arrow_labels, loc=2, fontsize='small')
        plt.show()

    def get_unvisited_vertices_and_ending_vertices(self):
        last_visited_vertex = None
        unvisited_vertices = list([])
        ending_vertices = list([])
        for vertex in self.route.vertices:
            if not vertex.visited:
                unvisited_vertices.append(vertex)
                if last_visited_vertex is not None:
                    ending_vertices.append(last_visited_vertex)
            last_visited_vertex = vertex
        ending_vertices.append(self.route.vertices[-1])

        return unvisited_vertices, ending_vertices

    def edge_create_circular_path(self, edge):
        starting_vertex = edge.vertices[0]
        ending_vertex = edge.vertices[1]
        initial_ending_vertex = ending_vertex

        while True:
#            print(starting_vertex)
            edge_matching_starting_vertex = self.route.get_edge_by_vertex_id(starting_vertex.vertex_id, 1)

            if edge_matching_starting_vertex is None:
                break
            else:
                if edge_matching_starting_vertex.vertices[0].vertex_id == initial_ending_vertex.vertex_id:
                    return True

                starting_vertex = edge_matching_starting_vertex.vertices[0]
                ending_vertex = edge_matching_starting_vertex.vertices[1]

        return False

    def complete_graph_greedy_heuristic(self, superiority_tolerance=0.8):
        self.route.reset_route()
        starting_vertex = None

        # Update route to match current representation given superiority_tolerance
        superiority_edges = [(edge_key, edge_entry) for (edge_key, edge_entry) in self.edge_dictionary.items() if edge_entry.edge_count >= (self.max_edge_count * superiority_tolerance)]

        for edge_key, edge_entry in superiority_edges:
            better_edge = False
            for edge_key_1, edge_entry_1 in superiority_edges:
                if edge_entry.edge.vertices[0].vertex_id == edge_entry_1.edge.vertices[0].vertex_id or edge_entry.edge.vertices[1].vertex_id == edge_entry_1.edge.vertices[1].vertex_id:
                    if edge_entry.edge_count == edge_entry_1.edge_count:
                        if edge_entry.edge.distance > edge_entry_1.edge.distance:
                            better_edge = True
                    elif edge_entry.edge_count < edge_entry_1.edge_count:
                        better_edge = True

            if not better_edge:
                if self.route.edges is None:
                    self.route.add_edge(edge_entry.edge)
                else:
                    if not self.edge_create_circular_path(edge_entry.edge):
                        self.route.add_edge(edge_entry.edge)
        self.route.distance_traveled = self.route.recount_distance()

        def choose_next_vertex():
            closest_item_next_to_closest_vertex = None
            r_type_of_closest_item = None
            closest_vertex = None
            closest_distance = None
            starting_vertex = self.route.vertices[0]

            for vertex in self.route.get_vertices_not_in_route():
                closest_item_next_to_vertex, item_distance = self.route.get_shortest_distance_to_route(vertex)

                if closest_vertex is None:
                    closest_vertex = vertex
                    closest_distance = item_distance
                    closest_item_next_to_closest_vertex = closest_item_next_to_vertex
                else:
                    if item_distance < closest_distance:
                        closest_distance = item_distance
                        closest_vertex = vertex
                        closest_item_next_to_closest_vertex = closest_item_next_to_vertex

            if len(self.route.get_unvisited_vertices()) == 0:
                return self.route.vertices[0], self.route.vertices[1]
            else:
                return closest_vertex, closest_item_next_to_closest_vertex

        while len(self.route.vertices) < len(self.route.graph.vertices):
            next_vertex, closest_item_next_to_vertex = choose_next_vertex()
            self.route.lasso(next_vertex, closest_item_next_to_vertex)

        self.route.greedy_recombine()

        return self.route

    class EdgeEntry(object):
        def __init__(self, edge_key, edge_count, edge):
            self.edge_key = edge_key
            self.edge_count = edge_count
            self.edge = edge

        def __eq__(self, other):
            return self.edge_key == other.edge_key

        def __lt__(self, other):
            return self.edge_count < other.edge_count

        def __le__(self, other):
            return self.edge_count <= other.edge_count

        def __gt__(self, other):
            return self.edge_count > other.edge_count

        def __ge__(self, other):
            return self.edge_count >= other.edge_count

        def __str__(self):
            return "[edge_key: " + str(self.edge_key) + ", edge_count: " + str(self.edge_count) + ", edge: " + str(self.edge) + "]"

        def increment(self):
            self.edge_count += 1
Пример #9
0
    def brute_force_solution(graph,
                             current_vertex_id=1,
                             reduce_ram_usage=False):
        # Generate route log path
        if reduce_ram_usage:
            route_log_path =os.getcwd() + os.path.sep + ".." + os.path.sep + "logs" + os.path.sep + \
                            "RouteLog_{0}_{1}".format(len(graph.vertices), str(time.time())[:9])

        # Recursive function for trying all adjacent vertices.
        def try_all_open_routes_from_current_route(route,
                                                   reduce_ram_usage=False):
            # Initialize Routes to keep track of all attempted routes.
            routes = np.array([])
            # Start at the current vertex id location
            current_vertex = route.graph.vertices[current_vertex_id]

            # For each adjacent vertex that has not been visited
            for adjacent_vertex in current_vertex.get_unvisited_adjacent_vertex_ids(
            ):
                # copy the route so far
                new_route = deepcopy(route)
                # goto the current adjacent_vertex
                new_route.goto(adjacent_vertex.vertex_id)

                # if all vertices have been visisted
                if new_route.graph.finished():
                    # goto the current vertex id
                    new_route.goto(current_vertex_id)

                    if reduce_ram_usage:
                        # Log finished route to hard disk
                        FileHandler.log_route(new_route, route_log_path)
                        # Delete from RAM
                        del new_route
                    else:
                        # append the route to the list of completed routes
                        routes = np.concatenate((routes, new_route), axis=None)
                else:  # if not,
                    if reduce_ram_usage:
                        try_all_open_routes_from_current_route(
                            new_route, reduce_ram_usage)
                    else:
                        # Recall the recursive function using the updated route.
                        routes = np.concatenate((
                            routes,
                            try_all_open_routes_from_current_route(new_route)),
                                                axis=None)

            # After all adjacent vertices have been visisted recursively, return the list of routes
            return routes

        # Initialize the route
        route = Route(list([]), graph)
        # goto the current vertex id
        route.goto(current_vertex_id)

        # Initialize a list of routes
        routes = np.array([])

        # Recursively try all open routes from the current route, advancing when possible.
        routes = np.concatenate(
            (routes,
             try_all_open_routes_from_current_route(
                 route, reduce_ram_usage=reduce_ram_usage)),
            axis=None)

        if reduce_ram_usage:
            del routes
            # Sift file located at route_log_path for the shortest route
            return FileHandler.find_minimum_route(route_log_path)
        else:
            # Identify the route with minimum distance traveled
            return min(routes)
Пример #10
0
    class GreedyAlgorithm(object):
        def __init__(self, graph, starting_vertex_id=1, reset_heuristic=False):
            self.route = Route(graph)
            self.starting_vertex_id = starting_vertex_id
            self.route.goto(
                self.route.graph.get_vertex_by_id(starting_vertex_id))
            self.done = False
            self.attempted_starting_vertex_ids = list([starting_vertex_id])
            self.remaining_starting_vertex_ids = self.get_remaining_starting_vertex_ids(
            )
            self.reset_heuristic = reset_heuristic
            self.crosses = 0

        def __eq__(self, other):
            return self.route.distance_traveled == other.route.distance_traveled

        def __lt__(self, other):
            return self.route.distance_traveled < other.route.distance_traveled

        def __le__(self, other):
            return self.route.distance_traveled <= other.route.distance_traveled

        def __gt__(self, other):
            return self.route.distance_traveled > other.route.distance_traveled

        def __ge__(self, other):
            return self.route.distance_traveled >= other.route.distance_traveled

        def __str__(self):
            string = "Starting vertex id: " + str(
                self.starting_vertex_id) + "\n"

            string += "Route: " + str(self.route) + "\n"

            string += "reset_heuristic: " + str(self.reset_heuristic) + "\n"

            string += "Crosses: " + str(self.crosses)

            return string

        def complete(self):
            while not self.done:
                self.step_forward()

            return self.route

        def step_forward(self):
            next_vertex, closest_item_next_to_vertex = self.choose_next_vertex(
            )
            self.route.lasso(next_vertex, closest_item_next_to_vertex)

            if len(self.route.vertices) > len(self.route.graph.vertices):
                self.done = True

        def step_backward(self):
            if len(self.route.vertices) > 0:
                self.route.walk_back()
                self.attempted_starting_vertex_ids.pop()
                self.remaining_starting_vertex_ids = self.get_remaining_starting_vertex_ids(
                )

                if self.done:
                    self.done = False

        def choose_next_vertex(self):
            closest_item_next_to_closest_vertex = None
            r_type_of_closest_item = None
            closest_vertex = None
            closest_distance = None

            for vertex in self.route.get_unvisited_vertices():
                closest_item_next_to_vertex, item_distance = self.route.get_shortest_distance_to_route(
                    vertex)

                if closest_vertex is None:
                    closest_vertex = vertex
                    closest_distance = item_distance
                    closest_item_next_to_closest_vertex = closest_item_next_to_vertex
                else:
                    if item_distance < closest_distance:
                        closest_distance = item_distance
                        closest_vertex = vertex
                        closest_item_next_to_closest_vertex = closest_item_next_to_vertex

            if len(self.route.get_unvisited_vertices()) == 0:
                return self.route.vertices[0], self.route.vertices[1]
            else:
                return closest_vertex, closest_item_next_to_closest_vertex

        def get_remaining_starting_vertex_ids(self):
            return [
                vertex_id for vertex_id in list(
                    range(1,
                          len(self.route.graph.vertices) + 1))
                if vertex_id not in self.attempted_starting_vertex_ids
            ]
Пример #11
0
def build_chromosome_from_path_and_graph(chromosome_id, path, graph,
                                         crossover_method, mutation_method):
    route = Route(graph)
    route.walk_complete_path(path)
    return GeneticAlgorithm.Chromosome(chromosome_id, route, crossover_method,
                                       mutation_method)
Пример #12
0
        def crossover(self, other_chromosome):
            new_path = list([])

            if self.crossover_method == GeneticAlgorithm.Chromosome.CrossoverMethods.UNIFORM:
                self_turn = True

                while len(new_path) < len(self.route.vertices) - 1:
                    if self_turn:
                        remaining_vertex_ids = [
                            vertex.vertex_id for vertex in self.route.vertices
                            if vertex.vertex_id not in new_path
                        ]
                        if len(remaining_vertex_ids) > 0:
                            new_path.append(
                                random.choice(remaining_vertex_ids))

                        self_turn = False
                    else:
                        remaining_vertex_ids = [
                            vertex.vertex_id
                            for vertex in other_chromosome.route.vertices
                            if vertex.vertex_id not in new_path
                        ]
                        if len(remaining_vertex_ids) > 0:
                            new_path.append(
                                random.choice(remaining_vertex_ids))

                        self_turn = True

            elif self.crossover_method == GeneticAlgorithm.Chromosome.CrossoverMethods.PARTIALLY_MAPPED:
                p1 = random.randint(1, len(self.route.vertices) - 3)
                p2 = random.randint(p1 + 1, len(self.route.vertices) - 2)

                self_ids = [
                    vertex.vertex_id for vertex in self.route.vertices
                ][:-1]
                self_s1 = self_ids[:p1]
                self_s2 = self_ids[p1:p2]
                self_s3 = self_ids[p2:]

                other_ids = [
                    vertex.vertex_id
                    for vertex in other_chromosome.route.vertices
                ][:-1]
                other_s1 = other_ids[:p1]
                other_s2 = other_ids[p1:p2]
                other_s3 = other_ids[p2:]

                new_path = self_s1

                s2_left = list([])
                for vertex_id in other_s2:
                    if vertex_id not in self_s1 and vertex_id not in self_s3:
                        s2_left.append(vertex_id)

                s3_left = list([])
                for vertex_id in other_s3:
                    if vertex_id not in self_s1 and vertex_id not in self_s3:
                        s3_left.append(vertex_id)

                s1_left = list([])
                for vertex_id in other_s1:
                    if vertex_id not in self_s1 and vertex_id not in self_s3:
                        s1_left.append(vertex_id)

                remaining_vertex_ids = s2_left + s3_left + s1_left
                new_path += remaining_vertex_ids[:p2 - p1]

                new_path += self_s3

            elif self.crossover_method == GeneticAlgorithm.Chromosome.CrossoverMethods.ORDERED_CROSSOVER:
                p1 = random.randint(1, len(self.route.vertices) - 3)
                p2 = random.randint(p1 + 1, len(self.route.vertices) - 2)
                j_1 = p1 + 1
                j_2 = j_1
                k = j_1

                to_p1 = self.route.vertices[:p1]
                from_p1 = self.route.vertices[p1:]
                mid = other_chromosome.route.vertices[p1:p2 + 1]

                for vertex in to_p1:
                    if vertex not in mid:
                        new_path.append(vertex.vertex_id)

                for vertex in mid:
                    new_path.append(vertex.vertex_id)

                for vertex in from_p1:
                    if vertex.vertex_id not in new_path:
                        new_path.append(vertex.vertex_id)

            else:  # Splits the two chromosomes down the middle
                index = 0

                while len(new_path) < len(self.route.vertices) - 1:
                    if index < len(self.route.vertices) // 2:
                        if self.route.vertices[
                                index].vertex_id not in new_path:
                            new_path.append(
                                self.route.vertices[index].vertex_id)
                            index += 1
                    else:
                        remaining_vertices = [
                            vertex for vertex in self.route.vertices
                            if vertex.vertex_id not in new_path
                        ]
                        for remainining_vertex in remaining_vertices:
                            new_path.append(remainining_vertex.vertex_id)

            new_route = Route(self.route.graph)
            new_route.walk_complete_path(new_path)

            resultant_chromosome = GeneticAlgorithm.Chromosome(
                None, new_route, self.crossover_method, self.mutation_method)

            return resultant_chromosome