def update_pop_t(ret): """ This is a callback function of a process, purpose1: update pop_t, i.e, store the new generated offspring in pop_t purpose2: update best_feasible_solution, cause we need to return a best feasible solution when time out. :param ret: s_x, s_ls, lmd = ret[0], ret[1], ret[2] """ global pop_t global Graph s_x, s_ls, lmd = ret[0], ret[1], ret[2] if s_x is None and s_ls is None: # only when the time is coming up, the process will directly stop and return None return if s_ls is None: # just do crossover, not do local search if not is_clone(s_x, pop_t): heapq.heappush(pop_t, (evaluation_solution(s_x, Graph, lmd), s_x)) else: # do both cross over and local search if not is_clone(s_ls, pop_t): heapq.heappush(pop_t, (evaluation_solution(s_ls, Graph, lmd), s_ls)) elif not is_clone(s_x, pop_t): heapq.heappush(pop_t, (evaluation_solution(s_x, Graph, lmd), s_x)) global best_feasible_solution # pop_t[0] means the heap top--> (cost,solution) # pop_t[0][0] means the heap top cost, # pop_t[0][1] means the heap top solution if is_feasible(pop_t[0][1], Graph) and pop_t[0][0] < best_feasible_solution['cost']: best_feasible_solution["cost"] = pop_t[0][0] best_feasible_solution['solution'] = pop_t[0][1]
def ms_operators(s_x, graph, lmd): generated = set() traversed = False for i in range(100): # find two routes from current solutions a, b = generate_two_random(0, len(s_x) - 1) cnt = 0 while (a, b) in generated: cnt += 1 if cnt > 200: traversed = True break a, b = generate_two_random(0, len(s_x) - 1) if traversed or (a, b) in generated: continue generated.add((a, b)) parted_tasks = s_x[a] + s_x[b] reverse_tasks = [(item[1], item[0]) for item in parted_tasks] parted_tasks += reverse_tasks # before cost before_cost = evaluation_solution([s_x[a], s_x[b]], graph, lmd) # after cost s, cost = ms_operator(parted_tasks, graph, lmd) # update current solution if cost < before_cost: current_solutions = copy.deepcopy(s_x) current_solutions[a] = [] current_solutions[b] = [] current_solutions += s current_solutions = [ item for item in current_solutions if item != [] ] return current_solutions return None
def double_insertion(s, graph, lmd): s_t = copy.deepcopy(s) min_cost = float('inf') pos = (0, 0, 0, 0) for i, route in enumerate(s_t): if len(route) >= 2: for j in range(len(route) - 1): double_tasks = route[j:j + 2] del route[j] del route[j] for x, r in enumerate(s_t): for y in range(len(r) + 1): s_t[x].insert(y, double_tasks[1]) s_t[x].insert(y, double_tasks[0]) cost = evaluation_solution(s_t, graph, lmd) if cost <= min_cost: min_cost, pos = cost, (i, j, x, y) del s_t[x][y] del s_t[x][y] route.insert(j, double_tasks[1]) route.insert(j, double_tasks[0]) i, j, x, y = pos double_tasks = s_t[i][j:j + 2] del s_t[i][j] del s_t[i][j] s_t[x].insert(y, double_tasks[1]) s_t[x].insert(y, double_tasks[0]) if len(s_t[i]) == 0: del s_t[i] return s_t, min_cost
def init_population(graph, tasks, print_initial=False): current_population = [] while len(current_population) < 2000: ntrail = 0 end = False while 1: individual = path_scanning(graph=graph, tasks=tasks) ntrail += 1 if not is_clone(individual, current_population): break if ntrail == Configuration.ubtrial: # generate a duplicated individual,count until get upper bound end = True break if end: break heapq.heappush( current_population, (evaluation_solution(individual, graph, lmd=0), individual)) result = [] # select p_size best individuals as initial population if print_initial: print("Finish initial population, only print top 3.") for i in range(Configuration.psize): item = heapq.heappop(current_population) if print_initial and i < 3: print(item) result.append(item[1]) return result
def ms_operator(parted_tasks, graph, lmd): best = None min_cost = float('inf') for i in range(1, 6): s = path_scanning(graph, parted_tasks) # TODO Ulusoy's splitting procedure c = evaluation_solution(s, graph, lmd) if c <= min_cost: min_cost = c best = s return best, min_cost
def swap(s, graph, lmd): s_t = copy.deepcopy(s) min_cost = float('inf') pos = (0, 0, 0, 0) for i, route in enumerate(s_t): for j, task in enumerate(route): for x, route2 in enumerate(s_t): for y, task2 in enumerate(route2): if x > i or (x == i and y >= j): tmp = s_t[x][y] s_t[x][y] = s_t[i][j] s_t[i][j] = tmp cost = evaluation_solution(s_t, graph, lmd) if cost <= min_cost: min_cost, pos = cost, (i, j, x, y) s_t[i][j] = s_t[x][y] s_t[x][y] = tmp i, j, x, y = pos tmp = s_t[x][y] s_t[x][y] = s_t[i][j] s_t[i][j] = tmp return s_t, min_cost
def single_insertion(s, graph, lmd): s_t = copy.deepcopy(s) min_cost = float('inf') pos = (0, 0, 0, 0) for i, route in enumerate(s_t): for j in range(len(route)): task = route[j] del route[j] for x, r in enumerate(s_t): for y in range(len(r) + 1): s_t[x].insert(y, task) cost = evaluation_solution(s_t, graph, lmd) if cost <= min_cost: min_cost, pos = cost, (i, j, x, y) del s_t[x][y] route.insert(j, task) i, j, x, y = pos task = s_t[i][j] del s_t[i][j] s_t[x].insert(y, task) if len(s_t[i]) == 0: del s_t[i] return s_t, min_cost
def MAENS(start, graph, tasks, time_limit, mul_process=False): """ :param start: the start run time of this program :param time_limit: the run time limit of MAENS algorithms :param graph: is the graph read from data set, include following attributes: {"adjacent_matrix": the adjacent matrix presentation of the graph, "adjacent_table": the adjacent table presentation of the graph, "demand_matrix": demand_matrix, "dijkstra_matrix": dijkstra_matrix[i][j] store the minimum distance between node i and node j "basic_infor": store the basic information of this graph, e.g., depot, capacity, required edges and so on, } :param tasks: an edge tuple list, store all the task need to be finish, notice, if (i, j) in tasks, then (j, i) in it also. :param mul_process: run MAENS on multiprocessing or not. :return: a feasible solution feasible within time limits. Example: -------- s 0,(1,2),(2,3),(3,5),0,0,(1,4),(4,2),(2,9),(4,3),(5,6),0,0,(1,12),(12,6),(6,7),(7,12),0,0,(1,10),(10,9), (9,11),(11,5),(5,12),0,0,(1,7),(7,8),(8,10),(10,11),(11,8),0 q 316 """ # initialization multiprocessing setting if mul_process: pool = Pool(processes=16) global Graph global pop_t global best_feasible_solution Graph = graph # generate a initial population by path_scanning # TODO support more initial population algorithms, e.g, Floyd Algorithm pop = init_population(graph, tasks, print_initial=True) stop_criterion = 0 while stop_criterion != Configuration.generation_cnt: # initial an iteration pop_t = [] for p in pop: # set an intermediate population pop_t = pop notice, pop_t is a heap and pop is a list heapq.heappush(pop_t, (evaluation_solution(p, graph, 0), p)) for p in pop: if is_feasible(p, graph): best_feasible_solution['cost'] = get_cost(p, graph) best_feasible_solution['solution'] = p break # multi processing code if mul_process: results = [] for i in range(Configuration.opsize): result = pool.apply_async( func=crossover_plus_local_search, args=(pop, graph, time_limit, start, best_feasible_solution['cost']), callback=update_pop_t) results.append(result) # wait an iteration to finish for r in results: r.wait() if time_limit - (time.time() - start) < 3: pool.close() pool.join() print_result(best_feasible_solution['solution'], graph, paint=True) return 0 # single processing code else: for i in range(Configuration.opsize): a, b = generate_two_random(0, len(pop) - 1) s_x = crossover(pop[a], pop[b], graph) r = generate_one_random(0, 1, flt=True) lmd = get_initial_lmd(best_feasible_solution['cost'], s_x, graph) if r < Configuration.p_ls: s_ls, lmd = local_search(s_x, graph, lmd) if not is_clone(s_ls, pop_t): heapq.heappush( pop_t, (evaluation_solution(s_ls, graph, lmd), s_ls)) elif not is_clone(s_x, pop_t): heapq.heappush( pop_t, (evaluation_solution(s_x, graph, lmd), s_x)) elif not is_clone(s_x, pop_t): heapq.heappush(pop_t, (evaluation_solution(s_x, graph, lmd), s_x)) # update pop with pop_t for i in range(len(pop)): item = heapq.heappop(pop_t) pop[i] = [task for task in item[1] if task != []] run_time = (time.time() - start) print("offspring %d generate current run_time is: %f" % (stop_criterion + 1, run_time)) print("current best feasible solution is:", best_feasible_solution) stop_criterion += 1 print_result(best_feasible_solution['solution'], graph, paint=True) return 0