code reworking WIP
This commit is contained in:
parent
11f6a75f74
commit
a60ce57e19
3 changed files with 77 additions and 81 deletions
51
run.py
51
run.py
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
"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:
|
class SolverTSP:
|
||||||
|
|
||||||
solution: ndarray
|
solution: ndarray
|
||||||
found_length: float
|
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,
|
def __init__(self, algorithm_name, problem_instance):
|
||||||
"2.5-opt": loop2dot5opt,
|
assert algorithm_name in available_solvers, f"the {algorithm_name} initializer is not available currently."
|
||||||
"simulated_annealing": sa}
|
self.duration = np.inf
|
||||||
|
self.algorithm_name = algorithm_name
|
||||||
# ,
|
self.algorithms = [algorithm_name]
|
||||||
# "simulated_annealing": Simulated_Annealing,
|
self.name_method = "initialized with " + algorithm_name
|
||||||
# "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
|
|
||||||
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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in a new issue