code reworking WIP

This commit is contained in:
Dario Mantegazza 2020-09-28 09:30:21 +02:00
parent 11f6a75f74
commit a60ce57e19
3 changed files with 77 additions and 81 deletions

51
run.py
View file

@ -1,57 +1,56 @@
import pandas as pd import pandas as pd
from src.io_tsp import Instance from src.io_tsp import ProblemInstance
from src.TSP_solver import SolverTSP from src.TSP_solver import SolverTSP, available_improvers, available_solvers
import numpy as np 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.bind(improve)
solver(instance, return_value=False, verbose=verbose) solver.compute_solution(return_value=False, verbose=verbose)
if verbose: if verbose:
print(f"the total length for the solution found is {solver.found_length}", 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 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)) 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: if show_plots:
solver.plot_solution() solver.plot_solution()
def run(show_plots=False, verbose=False): def run(show_plots=False, verbose=False):
# names = [name_ for name_ in os.listdir("./problems") if "tsp" in name_] # problems = glob.glob('./problems/*.tsp')
names = ["eil76.tsp"] problems = ["./problems/eil76.tsp"]
initializers = SolverTSP.available_initializers.keys() solvers_names = available_solvers.keys()
improvements = SolverTSP.available_improvements.keys() improvers_names = available_improvers.keys()
results = [] results = []
index = [] index = []
for name in names: for problem_path in problems:
filename = f"problems/{name}" prob_instance = ProblemInstance(problem_path)
instance = Instance(filename)
if verbose: if verbose:
print("\n\n#############################") print("\n\n#############################")
instance.print_info() prob_instance.print_info()
if show_plots: if show_plots:
instance.plot_data() prob_instance.plot_data()
for init in initializers: for solver_name in solvers_names:
for improve in improvements: for improve in improvers_names:
solver = SolverTSP(init) solver = SolverTSP(solver_name, prob_instance)
add(solver, instance, improve, index, results, name, verbose, show_plots) add(solver, improve, index, results, problem_path, verbose, show_plots)
for improve2 in [j for j in improvements if j not in [improve]]: for improve2 in [j for j in improvers_names if j not in [improve]]:
add(solver, instance, improve2, index, results, name, verbose, show_plots) add(solver, improve2, index, results, problem_path, verbose, show_plots)
for improve3 in [j for j in improvements if j not in [improve, improve2]]: for improve3 in [j for j in improvers_names if j not in [improve, improve2]]:
add(solver, instance, improve3, index, results, name, verbose, show_plots) add(solver, improve3, index, results, problem_path, verbose, show_plots)
solver.pop() solver.pop()
solver.pop() solver.pop()
if instance.exist_opt and show_plots: if prob_instance.exist_opt and show_plots:
solver.solution = np.concatenate([instance.optimal_tour, [instance.optimal_tour[0]]]) solver.solution = np.concatenate([prob_instance.optimal_tour, [prob_instance.optimal_tour[0]]])
solver.method = "optimal" solver.method = "optimal"
solver.plot_solution() solver.plot_solution()

View file

@ -8,99 +8,95 @@ from src.two_dot_five_opt import loop2dot5opt
from src.simulated_annealing import sa from src.simulated_annealing import sa
from src.constructive_algorithms import random_method, nearest_neighbor, best_nearest_neighbor, multi_fragment_mf from src.constructive_algorithms import random_method, nearest_neighbor, best_nearest_neighbor, multi_fragment_mf
available_solvers = {"random": random_method,
class SolverTSP:
solution: ndarray
found_length: float
available_initializers = {"random": random_method,
"nearest_neighbors": nearest_neighbor, "nearest_neighbors": nearest_neighbor,
"best_nn": best_nearest_neighbor, "best_nn": best_nearest_neighbor,
"multi_fragment": multi_fragment_mf "multi_fragment": multi_fragment_mf
} }
available_improvements = {"2-opt": loop2opt, available_improvers = {"2-opt": loop2opt,
"2.5-opt": loop2dot5opt, "2.5-opt": loop2dot5opt,
"simulated_annealing": sa} "simulated_annealing": sa}
# ,
# "simulated_annealing": Simulated_Annealing,
# "iterated_local_search": Iterated_Local_Search}
def __init__(self, initializer): class SolverTSP:
# self.available_methods = {"random": self.random_method, "nearest_neighbors": self.nn, solution: ndarray
# "best_nn": self.best_nn, "multi_fragment": self.mf} found_length: float
self.initializer = initializer
self.methods = [initializer] def __init__(self, algorithm_name, problem_instance):
self.name_method = "initialized with " + initializer 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 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): def bind(self, local_or_meta):
assert local_or_meta in self.available_improvements, f"the {local_or_meta} method is not available currently." assert local_or_meta in available_improvers, f"the {local_or_meta} method is not available currently."
self.methods.append(local_or_meta) self.algorithms.append(local_or_meta)
self.name_method += ", improved with " + local_or_meta self.name_method += ", improved with " + local_or_meta
def pop(self): 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:][ self.name_method = self.name_method[::-1][self.name_method[::-1].find("improved"[::-1]) + len("improved") + 2:][
::-1] ::-1]
def __call__(self, instance_, verbose=True, return_value=True): def compute_solution(self, verbose=True, return_value=True):
self.instance = instance_
self.solved = False self.solved = False
if verbose: if verbose:
print(f"### solving with {self.methods} ####") print(f"### solving with {self.algorithms} ####")
start = t() start_time = t()
self.solution = self.available_initializers[self.methods[0]](instance_) 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" assert self.check_if_solution_is_valid(self.solution), "Error the solution is not valid"
for i in range(1, len(self.methods)): for i in range(1, len(self.algorithms)):
self.solution = self.available_improvements[self.methods[i]](self.solution, self.instance) 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" assert self.check_if_solution_is_valid(self.solution), "Error the solution is not valid"
end = t() end_time = t()
self.time_to_solve = np.around(end - start,3) self.duration = np.around(end_time - start_time, 3)
self.solved = True self.solved = True
self.evaluate_solution() self.evaluate_solution()
self._gap() self._gap()
if verbose: # if verbose:
print(f"### solution found with {self.gap} % gap in {self.time_to_solve} seconds ####") # print(f"### solution found with {self.gap} % gap in {self.duration} seconds ####",
print(f"the total length for the solution found is {self.found_length}", # f"the total length for the solution found is {self.found_length}",
f"while the optimal length is {self.instance.best_sol}", # f"while the optimal length is {prob_instance.best_sol}",
f"the gap is {self.gap}%", # f"the gap is {self.gap}%")
f"the solution is found in {self.time_to_solve} seconds", sep="\n")
if return_value: if return_value:
return self.solution return self.solution
def plot_solution(self): 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)) plt.figure(figsize=(8, 8))
self._gap() self._gap()
plt.title(f"{self.instance.name} solved with {self.name_method} solver, gap {self.gap}") plt.title(f"{self.problem_instance.name} solved with {self.name_method} solver, gap {self.gap}")
ordered_points = self.instance.points[self.solution] ordered_points = self.problem_instance.points[self.solution]
plt.plot(ordered_points[:, 1], ordered_points[:, 2], 'b-') plt.plot(ordered_points[:, 1], ordered_points[:, 2], 'b-')
plt.show() plt.show()
def check_if_solution_is_valid(self, solution): 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)]) # rights_values = np.sum(
if rights_values == self.instance.nPoints: # [self.check_validation(i, solution[:-1]) for i in np.arange(self.problem_instance.nPoints)])
return True rights_values = np.sum([1 if np.sum(solution[:-1] == i) == 1 else 0 for i in np.arange(self.problem_instance.nPoints)])
else: return rights_values == self.problem_instance.nPoints
return False # return True
# else:
# return False
def check_validation(self, node, solution): # def check_validation(self, node, solution):
if np.sum(solution == node) == 1: # if np.sum(solution == node) == 1:
return 1 # return 1
else: # else:
return 0 # return 0
def evaluate_solution(self, return_value=False): def evaluate_solution(self, return_value=False):
total_length = 0 total_length = 0
starting_node = self.solution[0] starting_node = self.solution[0]
from_node = starting_node from_node = starting_node
for node in self.solution[1:]: 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 from_node = node
self.found_length = total_length self.found_length = total_length
@ -109,4 +105,5 @@ class SolverTSP:
def _gap(self): def _gap(self):
self.evaluate_solution(return_value=False) 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)

View file

@ -6,7 +6,7 @@ from numpy.core._multiarray_umath import ndarray
from src.utils import distance_euc from src.utils import distance_euc
class Instance: class ProblemInstance:
nPoints: int nPoints: int
best_sol: int best_sol: int
name: str name: str