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
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 ]