This repository contains a framework for implementing and evaluating Traveling Salesman Problem (TSP) solvers. The goal is to find the shortest possible path that visits each city exactly once and returns to the starting city.
- Clone this repository
- Install dependencies:
pip install -r requirements.txtsolver_evaluation/
├── solvers.py # Solver implementations
├── evaluation_utils.py # Utility functions and classes
├── evaluate_existing_results.py # Main evaluation script
└── requirements.txt # Project dependencies
- Create your solver by subclassing
BaseSolverinsolvers.py. UseNearestNeighborSolveras a reference:
from typing import List
from .evaluation_utils import GraphV2Problem, Solution
from .solvers import BaseSolver
class YourSolver(BaseSolver):
def problem_transformations(self, problem: GraphV2Problem):
"""Transform problem into format needed by your solver"""
return problem.edges # Default transformation returns edge matrix
async def solve(self, formatted_problem, future_id: int) -> List[int]:
"""Implement your solving logic here"""
# formatted_problem contains the edge matrix
# Return a list of indices representing the tour
# Example: [0, 2, 1, 3, 0] for a 4-city problem
pass-
problem_transformations: Transforms the problem into a format your solver can use- Input: GraphV2Problem with nodes and edge distances
- Output: Any format your solver needs
-
solve: Core solving logic- Input: Transformed problem and future_id (for timeout tracking)
- Output: List of indices representing the tour
class NearestNeighborSolver(BaseSolver):
def problem_transformations(self, problem: GraphV2Problem):
return problem.edges
async def solve(self, formatted_problem, future_id: int) -> List[int]:
distance_matrix = formatted_problem
n = len(distance_matrix[0])
visited = [False] * n
route = []
# Start from node 0
current_node = 0
route.append(current_node)
visited[current_node] = True
# Visit nearest unvisited node
for _ in range(n - 1):
if self.future_tracker.get(future_id):
return None
nearest_distance = np.inf
nearest_node = None
for j in range(n):
if not visited[j] and distance_matrix[current_node][j] < nearest_distance:
nearest_distance = distance_matrix[current_node][j]
nearest_node = j
route.append(nearest_node)
visited[nearest_node] = True
current_node = nearest_node
# Return to start
route.append(route[0])
return route- Add your solver to
evaluate_existing_results.py:
from solvers import YourSolver
# Add your solver to test_solvers
test_solvers = [
NearestNeighbourSolver(),
YourSolver(),
# Add more solvers...
]- Run the evaluation:
python evaluate_existing_results.py- Check results in
evaluation_results/:
solver_scores.csv: Raw performance scoressolver_relative_scores.csv: Normalized relative performancerelative_score.png: Performance visualization
The framework evaluates solvers on:
- Solution Quality: Total path distance (lower is better)
- Runtime Performance: Time taken to find solution
- Relative Performance: How well your solver performs compared to others
- Study the problem structure in
GraphV2Problem - Analyze how NearestNeighborSolver works
- Consider these improvement areas:
- Better initial city selection
- Look-ahead strategies
- Local optimization
- Clustering for large problems
- Meta-heuristics (e.g., 2-opt, 3-opt)
- Fork the repository
- Create your solver implementation
- Test thoroughly
- Submit a pull request with your results