def short_route_swap(map, max_time, min_score, solution_output): """"Create hillclimber solution based on solution output.""" # Delete short routes from solution solution = delete_short_route(map, min_score, solution_output) # Return solution if all connections are already used if solution == False: return Solution(map, solution_output.routes) # Update connections that are unused data = RailNL(map).data solution = Solution(map, solution.routes) connections_left = update_connections( map, data, solution.routes)['amount_connections'] # Find stations with unused connection and add these to route for traject in solution.routes: new_solution = add_unused_connection(solution, map, data, traject, connections_left) if new_solution == False: return Solution(map, solution_output.routes) return Solution(map, new_solution.routes)
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 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 main(): # Evaluator evaluator = Evaluator() # HillClimb # solution = Solution(100, 50) # solution.start() # optimizer = HillClimb(100000) # optimizer.run(solution, evaluator.shiftedSphere, 1, 1) # Simulated Annealing solution = Solution(100, 100) solution.start() optimizer = SimulatedAnnealing(100000, 0) optimizer.run(solution, evaluator.shiftedSphere, 1, 3, 100)
def breadth_first(map, max_routes, max_time, min_score, depth, ratio): """Create solution consisting of set of routes based on breadth first algorithm. 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 """ # Get all data for stations in current map data = RailNL(map).data # Create list where routes can be added routes = [] # Keep track of fraction of used connections num_connections = len(all_connections(map)) connections = connections_station(data) # Create random routes until it is not possible anymore due to the constrains while len(routes) < max_routes and len( connections["used_connections"]) < num_connections: breadth_first_route(map, max_time, min_score, data, routes, depth, ratio, definition=None) connections = update_connections(map, data, routes) return Solution(map, routes)
def hillclimber(map, max_routes, max_time, min_score, solution, algorithm, depth, ratio, change_routes): """"Create hillclimber solution based on greedy output. Keyword arguments: algorithm (str) algorithm that will be used to improve solution 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 change_routes (int) amount of routes that can be improved """ # Get all data from stations in map data = RailNL(map).data # Set best solution which can should be improved best_solution = solution # Remove routes that needs to be changed last_solution = deepcopy(best_solution) last_solution = remove_routes(last_solution, change_routes) # Add routes to solution to get new solution new_routes = add_routes(map, max_time, min_score, data, last_solution, algorithm, depth, ratio, change_routes, "improve") new_solution = Solution(map, new_routes) # Change best solution if needed if new_solution.score > last_solution.score: best_solution = new_solution return best_solution
def solve(instance): master_problem_params = { 'SEC': None, 'activate_DB': False, 'min_visited_nodes': 0, 'time_limit': 3600 } subproblem_params = { 'M': sum( sorted( instance.truck_travel_time.values())[::-1][:2 * (instance.n - 1):2]) } functions = { 'get_route': get_route, 'get_route_recourse': get_route_recourse, 'get_shortcuts': get_shortcuts } master_problem = MasterProblem(instance, master_problem_params) subproblem = SubProblem(instance, subproblem_params) callback = Callback(instance, functions) solution = Solution(instance) cb = callback.callback(master_problem, subproblem, solution) solution.start_time = time() master_problem._solve(cb) solution.truck_arcs = [ a for a in instance.arcs if master_problem.variables['x'][a].X > 0.5 ] recourse = get_route_recourse(solution.truck_arcs, instance.arcs) subproblem.set_constr_rhs(recourse) subproblem._solve() solution.operations = [ e for e in instance.operations if subproblem.variables['o'][e].X > 0.5 ] plotter.plot(instance, solution.truck_arcs, solution.drone_arcs)
def simulated_annealing(map, max_routes, max_time, min_score, solution, algorithm, depth, ratio, change_routes, i, iterations, formula): """"Create hillclimber solution based on greedy output. Keyword arguments: algorithm (str) algorithm that will be used to improve solution 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 change_routes (int) amount of routes that can be improved i (int) ith iteration iterations (int) total iterations of improving formula (str) temperature formula """ # Get all data from stations in map data = RailNL(map).data # Set best solution which can should be improved best_solution = solution # Remove routes that needs to be changed last_solution = deepcopy(best_solution) last_solution = remove_routes(last_solution, change_routes) # Add routes to solution to get new solution new_routes = add_routes(map, max_time, min_score, data, last_solution, algorithm, depth, ratio, change_routes, "improve") new_solution = Solution(map, new_routes) # Set temperature depending of formula if formula == "linear": temperature = iterations / 2 - 0.5 * i elif formula == "exponential": temperature = iterations / 2 * (0.995**i) # Determine if new solution needs to be accepted acceptation_probability = 2**Decimal( (new_solution.score - last_solution.score) / Decimal(temperature)) random_probability = random() if acceptation_probability > random_probability: best_solution = new_solution return best_solution
def randomize(map, max_routes, max_time): """Create solution consisting of random routes.""" # Get all data of stations of current map data = RailNL(map).data # Make empty list for all routes routes = [] # Keep track of fraction of used connections num_connections = len(all_connections(map)) connections = connections_station(data) # Make random routes untill it is not possible anymore due to the constrains while len(routes) < max_routes and len( connections["used_connections"]) < num_connections: random_route(map, max_time, data, routes) connections = update_connections(map, data, routes) # Make solution class and update attributes random_solution = Solution(map, routes) return random_solution
def greedy(map, max_routes, max_time, key): """Create solution consisting of routes based on greedy algorithm. Keyword arguments: key (str) options: [Connections, Time, Score]. Method Greedy makes choices """ # Get all data from stations in map data = RailNL(map).data # Create list where routes can be added routes = [] # Keep track of fraction of used connections num_connections = len(all_connections(map)) connections = connections_station(data) # Make greedy routes until it is not possible anymore due to the constrains while len(routes) < max_routes and len( connections["used_connections"]) < num_connections: greedy_route(map, max_time, data, routes, key) connections = update_connections(map, data, routes) return Solution(map, routes)