def genetic_algorithm(sol, population_size, mutation_prob): l1_size = len(sol.level1) l2_size = len(sol.level2) clients_size = len(sol.clients) population = [generate_individual(l1_size, l2_size, clients_size) for x in range(population_size)] for ind in population: ind_sol = construct_from_RK(ind, sol) ind.func_obj = obj_function(ind_sol.level1, ind_sol.level2) population.sort(key=lambda x : x.func_obj) start_time = time.time() while time.time() - start_time < 60 * 0.05: sel_prob = normalize_obj_func(population) new_generation = [] for i in range(population_size): par1, par2 = parent_selection(sel_prob) par1 = population[par1] par2 = population[par2] son = crossover(par1, par2) if random() < mutation_prob: son = mutate(son) new_generation.append(son) # Calcular la función objetivo de la nueva generación for ind in new_generation: ind_sol = construct_from_RK(ind, sol) ind.func_obj = obj_function(ind_sol.level1, ind_sol.level2) population = population + new_generation population.sort(key=lambda x : x.func_obj) population = population[:population_size] return variable_neighborhood_descent(construct_from_RK(population[0], sol))
def variable_neighborhood_descent(sol): print('VND') cur_cost = obj_function(sol.level1, sol.level2) found_better = True neighborhoods = [inlevel_neighborhood, facility_inout_neighborhood] j = 0 while j < len(neighborhoods): best_cand = None best_cand_cost = inf for cand_sol, cost_delta in neighborhoods[j](sol): cand_cost = cur_cost + cost_delta if cand_cost < cur_cost: best_cand = cand_sol best_cand_cost = cand_cost break if best_cand_cost < cur_cost: j = 0 sol = best_cand cur_cost = best_cand_cost else: j += 1 return sol
def inlevel_neighborhood(sol): setup_solution(sol) initial_cost = obj_function(sol.level1, sol.level2) level2 = list(filter(lambda x: x.is_in, sol.level2)) for l2 in level2: for l1 in sol.level1: if l2.u[l1.i] == 0: continue cur_flow = l2.u[l1.i] for new_l2 in level2: if new_l2.i == l2.i: continue avail_cap = new_l2.m - new_l2.uSum flow_delta = min(avail_cap, cur_flow) if flow_delta == 0: continue func_obj_delta = flow_delta * sol.level2[new_l2.i].c[l1.i] - flow_delta * sol.level2[l2.i].c[l1.i] if func_obj_delta < 0: next_sol = sol.copy_solution(copyFlow=True) next_sol.level2[l2.i].u[l1.i] -= flow_delta next_sol.level2[new_l2.i].u[l1.i] += flow_delta else: next_sol = None yield next_sol, func_obj_delta
def random_method(level1, level2, clients, p, q, iterations=1): bestObj = inf ans_sel_level1, ans_sel_level2, ans_clients = None, None, None for i in range(iterations): # Elegir aleatoriamente p instalaciones sel_level1 = sample(level1, p) sel_level2 = sample(level2, q) sel_level1 = list(map(lambda x : x.new_clone(), sel_level1)) sel_level2 = list(map(lambda x : x.new_clone(), sel_level2)) # Calcular la asignación óptima usando MinCostMaxFlow cand_sel_level1, cand_sel_level2, cand_clients, flow, fcost = min_cost_max_flow(sel_level1, sel_level2, clients, p, q) cand_obj = obj_function(cand_sel_level1, cand_sel_level2) # Omit unfeasible solutions if flow != sum([x.d for x in clients]): continue if cand_obj < bestObj: ans_sel_level1, ans_sel_level2, ans_clients = cand_sel_level1, cand_sel_level2, cand_clients bestObj = cand_obj assert(ans_sel_level1 is not None) return ans_sel_level1, ans_sel_level2, ans_clients
def facility_inout_neighborhood(sol): setup_solution(sol) initial_cost = obj_function(sol.level1, sol.level2) l1_in = list(filter(lambda x : x.is_in, sol.level1)) l1_out = list(filter(lambda x : not x.is_in, sol.level1)) # Intercambiar instalaciones de nivel 1 for l_in in l1_in: for l_out in l1_out: if l_in.uSum <= l_out.m: func_obj_delta = 0 for i in range(len(l_in.u)): func_obj_delta += (l_out.u[i] - l_in.u[i]) * l_in.c[i] for i in range(len(l_in.u)): func_obj_delta += (l_in.u[i] - l_out.u[i]) * l_out.c[i] for l2 in sol.level2: func_obj_delta += (l2.u[l_out.i] - l2.u[l_in.i]) * l2.c[l_in.i] func_obj_delta += (l2.u[l_in.i] - l2.u[l_out.i]) * l2.c[l_out.i] if func_obj_delta < 0: next_sol = sol.copy_solution(copyFlow = True) next_l_in = next_sol.level1[l_in.i] next_l_out = next_sol.level1[l_out.i] next_l_in.is_in = False next_l_out.is_in = True next_l_in.u, next_l_out.u = next_l_out.u, next_l_in.u for l2 in next_sol.level2: l2.u[l_in.i], l2.u[l_out.i] = l2.u[l_out.i], l2.u[l_in.i] else: next_sol = None yield next_sol, func_obj_delta # Intercambiar instalaciones de nivel 2 l2_in = list(filter(lambda x : x.is_in, sol.level2)) l2_out = list(filter(lambda x : not x.is_in, sol.level2)) for l_in in l2_in: for l_out in l2_out: if l_in.uSum <= l_out.m: func_obj_delta = 0 for i in range(len(l_in.u)): func_obj_delta += (l_out.u[i] - l_in.u[i]) * l_in.c[i] for i in range(len(l_in.u)): func_obj_delta += (l_in.u[i] - l_out.u[i]) * l_out.c[i] if func_obj_delta < 0: next_sol = sol.copy_solution(copyFlow = True) next_l_in = next_sol.level2[l_in.i] next_l_out = next_sol.level2[l_out.i] next_l_in.is_in = False next_l_out.is_in = True next_l_in.u, next_l_out.u = next_l_out.u, next_l_in.u else: next_sol = None yield next_sol, func_obj_delta
def grasp(empty_sol, iterations = 10, k=5, rcl_method=rcl_constructive2): print('Method: {}'.format(rcl_method.__name__)) best_sol = None best_obj = inf for i in range(iterations): level1_temp, level2_temp, clients_temp = copy_solution(empty_sol.level1, empty_sol.level2, empty_sol.clients) sel_level1, sel_level2, clients = rcl_method(level1_temp, level2_temp, clients_temp, empty_sol.p, empty_sol.q, k = k) sel_solution = Solution(sel_level1, sel_level2, clients, empty_sol.p, empty_sol.q) empty_solution = Solution(empty_sol.level1, empty_sol.level2, empty_sol.clients, empty_sol.p, empty_sol.q) full_solution = mergeSolutions(sel_solution, empty_solution) func_obj = obj_function(full_solution.level1, full_solution.level2) #print('GRASP it {} starts with {:,.2f}'.format(i+1, func_obj)) sol = variable_neighborhood_descent(full_solution) func_obj = obj_function(sol.level1, sol.level2) #print('GRASP it {} ends with {:,.2f}'.format(i+1, func_obj)) if func_obj < best_obj: best_sol = sol best_obj = func_obj return best_sol
def local_search(sol): cur_cost = obj_function(sol.level1, sol.level2) print('initial cost: {:.2f}'.format(cur_cost)) found_better = True while found_better: found_better = False for next_sol, delta in facility_inout_neighborhood(sol): #cand_cost = obj_function(next_sol.level1, next_sol.level2) cand_cost = cur_cost + delta if cand_cost < cur_cost: print('new best') sol = next_sol cur_cost = cand_cost found_better = True break return sol