From a60ce57e1953850ba39bf7be3f190ef7ee67915e Mon Sep 17 00:00:00 2001 From: Dario Mantegazza Date: Mon, 28 Sep 2020 09:30:21 +0200 Subject: [PATCH] code reworking WIP --- run.py | 51 +++++++++++----------- src/TSP_solver.py | 105 ++++++++++++++++++++++------------------------ src/io_tsp.py | 2 +- 3 files changed, 77 insertions(+), 81 deletions(-) diff --git a/run.py b/run.py index 06984d4..96683ee 100644 --- a/run.py +++ b/run.py @@ -1,57 +1,56 @@ import pandas as pd -from src.io_tsp import Instance -from src.TSP_solver import SolverTSP +from src.io_tsp import ProblemInstance +from src.TSP_solver import SolverTSP, available_improvers, available_solvers import numpy as np -def add(solver, instance, improve, index, results, name, verbose, show_plots): +def add(solver, improve, index, results, name, verbose, show_plots): solver.bind(improve) - solver(instance, return_value=False, verbose=verbose) + solver.compute_solution(return_value=False, verbose=verbose) if verbose: print(f"the total length for the solution found is {solver.found_length}", - f"while the optimal length is {instance.best_sol}", + f"while the optimal length is {solver.problem_instance.best_sol}", f"the gap is {solver.gap}%", - f"the solution is found in {solver.time_to_solve} seconds", sep="\n") + f"the solution is found in {solver.duration} seconds", sep="\n") index.append((name, solver.name_method)) - results.append([solver.found_length, instance.best_sol, solver.gap, solver.time_to_solve]) + results.append([solver.found_length, solver.problem_instance.best_sol, solver.gap, solver.duration]) if show_plots: solver.plot_solution() def run(show_plots=False, verbose=False): - # names = [name_ for name_ in os.listdir("./problems") if "tsp" in name_] - names = ["eil76.tsp"] - initializers = SolverTSP.available_initializers.keys() - improvements = SolverTSP.available_improvements.keys() + # problems = glob.glob('./problems/*.tsp') + problems = ["./problems/eil76.tsp"] + solvers_names = available_solvers.keys() + improvers_names = available_improvers.keys() results = [] index = [] - for name in names: - filename = f"problems/{name}" - instance = Instance(filename) + for problem_path in problems: + prob_instance = ProblemInstance(problem_path) if verbose: print("\n\n#############################") - instance.print_info() + prob_instance.print_info() if show_plots: - instance.plot_data() + prob_instance.plot_data() - for init in initializers: - for improve in improvements: - solver = SolverTSP(init) - add(solver, instance, improve, index, results, name, verbose, show_plots) - for improve2 in [j for j in improvements if j not in [improve]]: - add(solver, instance, improve2, index, results, name, verbose, show_plots) + for solver_name in solvers_names: + for improve in improvers_names: + solver = SolverTSP(solver_name, prob_instance) + add(solver, improve, index, results, problem_path, verbose, show_plots) + for improve2 in [j for j in improvers_names if j not in [improve]]: + add(solver, improve2, index, results, problem_path, verbose, show_plots) - for improve3 in [j for j in improvements if j not in [improve, improve2]]: - add(solver, instance, improve3, index, results, name, verbose, show_plots) + for improve3 in [j for j in improvers_names if j not in [improve, improve2]]: + add(solver, improve3, index, results, problem_path, verbose, show_plots) solver.pop() solver.pop() - if instance.exist_opt and show_plots: - solver.solution = np.concatenate([instance.optimal_tour, [instance.optimal_tour[0]]]) + if prob_instance.exist_opt and show_plots: + solver.solution = np.concatenate([prob_instance.optimal_tour, [prob_instance.optimal_tour[0]]]) solver.method = "optimal" solver.plot_solution() diff --git a/src/TSP_solver.py b/src/TSP_solver.py index 99222b4..2b02e18 100644 --- a/src/TSP_solver.py +++ b/src/TSP_solver.py @@ -8,99 +8,95 @@ from src.two_dot_five_opt import loop2dot5opt from src.simulated_annealing import sa from src.constructive_algorithms import random_method, nearest_neighbor, best_nearest_neighbor, multi_fragment_mf +available_solvers = {"random": random_method, + "nearest_neighbors": nearest_neighbor, + "best_nn": best_nearest_neighbor, + "multi_fragment": multi_fragment_mf + } + +available_improvers = {"2-opt": loop2opt, + "2.5-opt": loop2dot5opt, + "simulated_annealing": sa} + class SolverTSP: - solution: ndarray found_length: float - available_initializers = {"random": random_method, - "nearest_neighbors": nearest_neighbor, - "best_nn": best_nearest_neighbor, - "multi_fragment": multi_fragment_mf - } - available_improvements = {"2-opt": loop2opt, - "2.5-opt": loop2dot5opt, - "simulated_annealing": sa} - - # , - # "simulated_annealing": Simulated_Annealing, - # "iterated_local_search": Iterated_Local_Search} - - def __init__(self, initializer): - # self.available_methods = {"random": self.random_method, "nearest_neighbors": self.nn, - # "best_nn": self.best_nn, "multi_fragment": self.mf} - self.initializer = initializer - self.methods = [initializer] - self.name_method = "initialized with " + initializer + def __init__(self, algorithm_name, problem_instance): + assert algorithm_name in available_solvers, f"the {algorithm_name} initializer is not available currently." + self.duration = np.inf + self.algorithm_name = algorithm_name + self.algorithms = [algorithm_name] + self.name_method = "initialized with " + algorithm_name self.solved = False - assert initializer in self.available_initializers, f"the {initializer} initializer is not available currently." + self.problem_instance = problem_instance def bind(self, local_or_meta): - assert local_or_meta in self.available_improvements, f"the {local_or_meta} method is not available currently." - self.methods.append(local_or_meta) + assert local_or_meta in available_improvers, f"the {local_or_meta} method is not available currently." + self.algorithms.append(local_or_meta) self.name_method += ", improved with " + local_or_meta def pop(self): - self.methods.pop() + self.algorithms.pop() self.name_method = self.name_method[::-1][self.name_method[::-1].find("improved"[::-1]) + len("improved") + 2:][ ::-1] - def __call__(self, instance_, verbose=True, return_value=True): - self.instance = instance_ + def compute_solution(self, verbose=True, return_value=True): self.solved = False if verbose: - print(f"### solving with {self.methods} ####") - start = t() - self.solution = self.available_initializers[self.methods[0]](instance_) + print(f"### solving with {self.algorithms} ####") + start_time = t() + self.solution = available_solvers[self.algorithms[0]](self.problem_instance) assert self.check_if_solution_is_valid(self.solution), "Error the solution is not valid" - for i in range(1, len(self.methods)): - self.solution = self.available_improvements[self.methods[i]](self.solution, self.instance) + for i in range(1, len(self.algorithms)): + self.solution = available_improvers[self.algorithms[i]](self.solution, self.problem_instance) assert self.check_if_solution_is_valid(self.solution), "Error the solution is not valid" - end = t() - self.time_to_solve = np.around(end - start,3) + end_time = t() + self.duration = np.around(end_time - start_time, 3) self.solved = True self.evaluate_solution() self._gap() - if verbose: - print(f"### solution found with {self.gap} % gap in {self.time_to_solve} seconds ####") - print(f"the total length for the solution found is {self.found_length}", - f"while the optimal length is {self.instance.best_sol}", - f"the gap is {self.gap}%", - f"the solution is found in {self.time_to_solve} seconds", sep="\n") + # if verbose: + # print(f"### solution found with {self.gap} % gap in {self.duration} seconds ####", + # f"the total length for the solution found is {self.found_length}", + # f"while the optimal length is {prob_instance.best_sol}", + # f"the gap is {self.gap}%") if return_value: return self.solution def plot_solution(self): - assert self.solved, "You can't plot the solution, you need to solve it first!" + assert self.solved, "You can't plot the solution, you need to compute it first!" plt.figure(figsize=(8, 8)) self._gap() - plt.title(f"{self.instance.name} solved with {self.name_method} solver, gap {self.gap}") - ordered_points = self.instance.points[self.solution] + plt.title(f"{self.problem_instance.name} solved with {self.name_method} solver, gap {self.gap}") + ordered_points = self.problem_instance.points[self.solution] plt.plot(ordered_points[:, 1], ordered_points[:, 2], 'b-') plt.show() def check_if_solution_is_valid(self, solution): - rights_values = np.sum([self.check_validation(i, solution[:-1]) for i in np.arange(self.instance.nPoints)]) - if rights_values == self.instance.nPoints: - return True - else: - return False + # rights_values = np.sum( + # [self.check_validation(i, solution[:-1]) for i in np.arange(self.problem_instance.nPoints)]) + rights_values = np.sum([1 if np.sum(solution[:-1] == i) == 1 else 0 for i in np.arange(self.problem_instance.nPoints)]) + return rights_values == self.problem_instance.nPoints + # return True + # else: + # return False - def check_validation(self, node, solution): - if np.sum(solution == node) == 1: - return 1 - else: - return 0 + # def check_validation(self, node, solution): + # if np.sum(solution == node) == 1: + # return 1 + # else: + # return 0 def evaluate_solution(self, return_value=False): total_length = 0 starting_node = self.solution[0] from_node = starting_node for node in self.solution[1:]: - total_length += self.instance.dist_matrix[from_node, node] + total_length += self.problem_instance.dist_matrix[from_node, node] from_node = node self.found_length = total_length @@ -109,4 +105,5 @@ class SolverTSP: def _gap(self): self.evaluate_solution(return_value=False) - self.gap = np.round(((self.found_length - self.instance.best_sol) / self.instance.best_sol) * 100, 2) + self.gap = np.round( + ((self.found_length - self.problem_instance.best_sol) / self.problem_instance.best_sol) * 100, 2) diff --git a/src/io_tsp.py b/src/io_tsp.py index ea9dd94..551380f 100644 --- a/src/io_tsp.py +++ b/src/io_tsp.py @@ -6,7 +6,7 @@ from numpy.core._multiarray_umath import ndarray from src.utils import distance_euc -class Instance: +class ProblemInstance: nPoints: int best_sol: int name: str