def greedy_route(map, max_time, data, routes, key): """Create a greedy route. Keyword arguments: key (str) options:[Connections, Time, Score]. Method Greedy makes choices """ # Make new empty route list and add (non-final) route to list of routes routes.append([]) # Pick a/the best station as starting point of the route routes[-1].append(greedy_option(map, data, routes, "connections")) # Keep adding stations to the route until constraints are met while greedy_option(map, data, routes, key) != None: routes[-1].append(greedy_option(map, data, routes, key)) # Check if route meets time constrain total_time = Route(map, routes).time if total_time > max_time: routes[-1] = routes[-1][:-1] break # Replace route list by final route object in list of routes routes[-1] = Route(map, routes) return routes[-1]
def breadth_first_route(map, max_time, min_score, data, routes, depth, ratio, definition): """Create a breadth first route. Keyword arguments: depth (int) length of route after which can be pruned ratio (int) score/length ratio in order to best solution after which can be pruned definition (str) options: [Create, Improve]. Goal of algorithm """ # Starting station of route chain = Queue() routes.append([]) start = [greedy_option(map, data, routes, "connections")] chain.put(start) # Set details for best route with breadth first algorithm best_route = Route(map, [start]) # Keep searching for routes until no feasible options while not chain.empty(): # Get top route/station from tree of routes state = chain.get() routes[-1] = state # Find each possible child from state and add to tree of routes if routes[-1][-1] != None and breadth_first_options( data, routes, definition) != None: for option in breadth_first_options(data, routes, definition): child = deepcopy(state) child.append(option) routes[-1] = child route = Route(map, routes) # Check time constrains for route if route.time < max_time: chain.put(child) # Apply Greedy look-ahead with minimal score or with score-route length ratio if len(route.route) > depth and ( route.score < min_score or (ratio - 1 / 20 * len(route.route)) * route.score / len(route.route) < best_route.score / len(best_route.route)): chain.get() # Check if route is best solution yet best_route = choose_best_route(route, best_route) routes[-1] = best_route return best_route
def random_options(map, data, routes): """Return possible destinations. Not possible to go to a station that is already on the route.""" # Determine amount of connections and used connections for all Stations routes[-1] = Route(map, routes[len(routes) - 1:]) connections = update_connections(map, data, routes) routes[-1] = routes[-1].route # Convert route of Station objects to route list of strings route_list = convert_object_to_string(routes[-1]) # Determine all possible connections from current station options = [] for connection in data[route_list[-1]].connections: possible_connection = (route_list[-1], connection[0]) if tuple(sorted( possible_connection)) not in connections["used_connections"]: options.append(connection[0]) # If any options, return random option if options: random_option = data[rd_choice(options)] return random_option return None
def delete_short_route(map, min_score, solution): """Delete short route or route that doesn't contribute to K score from route.""" old_score = solution.score # Find and delete routes that don't contribute to overall K score for route in solution.routes: if route.score < min_score: solution.routes.remove(route) routes = [] for i in range(len(solution.routes)): solution.routes[i] = solution.routes[i].route solution.routes[i] = Route(map, solution.routes[:i + 1]) # Calculate new K score new_score = Solution(map, solution.routes).score improvement = new_score - old_score # Update unused connections unused_connections = all_connections(map) - all_used_connections( Solution(map, solution.routes).routes) if unused_connections == set() or improvement <= 0: return False return Solution(map, solution.routes)
def bootstrap(cls, env, response): """ Bootstrap the application, send back headers and body """ cls.handle_wsgi_reboot(env) cls.build_request_obj(env) from classes.route import Route body = Route.init() cls.add_header('Content-type', 'text/html') cls.add_header('Content-Length', str(len(body))) response(cls.status, cls.headers) return [body]
def add_unused_connection(solution, map, data, traject, connections_left): """Add unused connection to route. Keyword arguments: traject (obj) route connections_left (list) list of unused connections tuples """ # Find station in route that can still make new connection for station in traject.route: if str(station) in connections_left.keys(): if connections_left[str(station)] >= 1: unused_connections = all_connections( map) - all_used_connections(solution.routes) # Break if all it's connections are used if unused_connections == set(): break # Find neighbour station that has no connection for connection in unused_connections: if str(connection[0]) == str(station): new_station = data[str(connection[1])] elif str(connection[1]) == str(station): new_station = data[str(connection[0])] else: return False # Create temporary route with unconnected station added to calculate new score index = traject.route.index(station) first_part = list(traject.route[:index + 1]) last_part = list(traject.route[index:]) temp_route = first_part + [new_station] + last_part # Calculate score based on solution with temporary route added copy_routes = deepcopy(solution) route_index = solution.routes.index(traject) copy_routes.routes[route_index].route = Route( map, [temp_route]).route temp_score = Solution(map, copy_routes.routes).score score_original = solution.score # Add station to route if score has improved if temp_score > score_original: solution.routes[route_index] = copy_routes.routes[ route_index] break return Solution(map, solution.routes)
def random_route(map, max_time, data, routes): """Randomize a route.""" # Make new empty route list and add (non-final) route to list of routes routes.append([]) total_time = 0 # Pick a random station as starting point of the route routes[-1].append(data[rd_choice(list(data.keys()))]) # Keep adding stations to the route until no more possible destinations while random_options(map, data, routes) != None: routes[-1].append(random_options(map, data, routes)) # Check if route meets time constrain, if not end route total_time = Route(map, routes).time if total_time > max_time: routes[-1] = routes[-1][:-1] break # Replace route list by final route object in list of routes routes[-1] = Route(map, routes) return routes[-1]
def greedy_option(map, data, routes, key): """Determine best destination. Keyword arguments: key (str) options:[Connections, Time, Score]. Method Greedy makes choices """ # Determine amount of connections and used connections for all stations routes[-1] = Route(map, routes[len(routes) - 1:]) connections = update_connections(map, data, routes) routes[-1] = routes[-1].route options = {} # Choose best option (not yet in route) from current station based on minimum of connections or time if key == "connections" or key == "time": # Convert route of Station objects to route list of strings route_list = convert_object_to_string(routes[-1]) # Check if route has station. If so, determine (unused) connections of current station if route_list != []: for connection in data[route_list[-1]].connections: possible_connection = (route_list[-1], connection[0]) # Check if connection has not yet been made, then add station to dict with corresponding amount of connections if tuple(sorted(possible_connection) ) not in connections["used_connections"]: if key == "connections": options[connection[0]] = connections[ "amount_connections"][connection[0]] elif key == "time": options[connection[0]] = connection[1] # All stations possible as starting station else: options = connections["amount_connections"] # If any options, choose best option which has least connections if options: best_option = data[rd_choice([ k for k, v in options.items() if v == min(list(options.values())) ])] return best_option return None elif key == "score": # Check if route has station. If so, determine (unused) connections of current station if routes[-1] != []: # Make list of already used connections in current route for connection in routes[-1][-1].connections: possible_connection = (routes[-1][-1].name, connection[0]) # Check if connection has not yet been made, then add station to dict with corresponding amount of connections if tuple(sorted(possible_connection) ) not in connections["used_connections"]: possible_routes = [] possible_route = routes[-1].copy() possible_routes.append(possible_route) possible_route.append(data[connection[0]]) options[connection[0]] = Route(map, possible_routes).score # All stations possible as starting station else: options = connections["amount_connections"] # If any options, choose best option which has least connections if options: best_option = data[rd_choice([ k for k, v in options.items() if v == max(list(options.values())) ])] return best_option return None