From 6ccc1cb66131b0a10865bcf45dbcb20dc954c0ae Mon Sep 17 00:00:00 2001 From: coolneng Date: Tue, 22 Jun 2021 08:37:38 +0200 Subject: [PATCH] Implement multi-start local search --- src/local_search.py | 49 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/local_search.py b/src/local_search.py index 06f6834..7ead8ad 100644 --- a/src/local_search.py +++ b/src/local_search.py @@ -1,5 +1,8 @@ from numpy.random import choice, seed, randint from pandas import DataFrame +from multiprocessing import Pool +from functools import partial +from itertools import combinations def get_row_distance(source, destination, data): @@ -22,7 +25,7 @@ def compute_distance(element, solution, data): return accumulator -def get_first_random_solution(n, m, data): +def get_first_random_solution(placeholder, n, m, data): solution = DataFrame(columns=["point", "distance"]) seed(42) solution["point"] = choice(n, size=m, replace=False) @@ -67,9 +70,41 @@ def explore_neighbourhood(element, n, data, max_iterations=100000): return neighbour -def local_search(n, m, data): - first_solution = get_first_random_solution(n, m, data) - best_solution = explore_neighbourhood( - element=first_solution, n=n, data=data, max_iterations=100 - ) - return best_solution +def evaluate_solution(solution, data): + fitness = 0 + comb = combinations(solution.index, r=2) + for index in list(comb): + elements = solution.loc[index, :] + fitness += get_row_distance( + source=elements["point"].head(n=1).values[0], + destination=elements["point"].tail(n=1).values[0], + data=data, + ) + return fitness + + +def generate_initial_solutions(n, m, data, number_solutions, cores=4): + generation_func = partial(get_first_random_solution, n=n, m=m, data=data) + with Pool(cores) as pool: + initial_solutions = pool.map(generation_func, range(number_solutions)) + return initial_solutions + + +def evaluate_all_solutions(solutions, data, cores=4): + generation_func = partial(evaluate_solution, data=data) + with Pool(cores) as pool: + fitness = pool.map(generation_func, solutions) + return fitness + + +def local_search(n, m, data, number_solutions=10): + initial_solutions = generate_initial_solutions(n, m, data, number_solutions) + solutions = [] + for solution in initial_solutions: + local_best_solution = explore_neighbourhood( + element=solution, n=n, data=data, max_iterations=100 + ) + solutions.append(local_best_solution) + fitness = evaluate_all_solutions(solutions, data) + best_index = fitness.index(max(fitness)) + return solutions[best_index]