Skip to content

Commit

Permalink
Attempt to handle Issue #53 (#54)
Browse files Browse the repository at this point in the history
* Setup test that should be satisfied when bug is solved

* fixup! Fix wrong usage of parametrize and skip test

* fix: Lin-Kernighan solver handles problems with few nodes

* fix: type hint

* feat: verbose flag when solving with brute force

---------

Co-authored-by: Luan <[email protected]>
  • Loading branch information
fillipe-gsm and Luan committed Apr 8, 2024
1 parent 3740b38 commit 4416f56
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
33 changes: 32 additions & 1 deletion python_tsp/heuristics/lin_kernighan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import numpy as np

from python_tsp.exact import solve_tsp_brute_force
from python_tsp.utils import setup_initial_solution


Expand Down Expand Up @@ -138,6 +139,33 @@ def _print_message(
print(msg)


def _solve_tsp_brute_force(
distance_matrix: np.ndarray,
log_file: Optional[str] = None,
verbose: bool = False,
) -> Tuple[List[int], float]:
x, fx = solve_tsp_brute_force(distance_matrix)
x = x or []

log_file_handler = (
open(log_file, "w", encoding="utf-8") if log_file else None
)
msg = (
"Few nodes to use Lin-Kernighan heuristics, "
"using Brute Force instead. "
)
if not x:
msg += "No solution found."
else:
msg += f"Found value: {fx}"
_print_message(msg, verbose, log_file_handler)

if log_file_handler:
log_file_handler.close()

return x, fx


def solve_tsp_lin_kernighan(
distance_matrix: np.ndarray,
x0: Optional[List[int]] = None,
Expand Down Expand Up @@ -173,10 +201,13 @@ def solve_tsp_lin_kernighan(
Éric D. Taillard, "Design of Heuristic Algorithms for Hard Optimization,"
Chapter 5, Section 5.3.2.1: Lin-Kernighan Neighborhood, Springer, 2023.
"""
num_vertices = distance_matrix.shape[0]
if num_vertices < 4:
return _solve_tsp_brute_force(distance_matrix, log_file, verbose)

hamiltonian_cycle, hamiltonian_cycle_distance = setup_initial_solution(
distance_matrix=distance_matrix, x0=x0
)
num_vertices = distance_matrix.shape[0]
vertices = list(range(num_vertices))
iteration = 0
improvement = True
Expand Down
22 changes: 19 additions & 3 deletions tests/heuristics/test_lin_kernighan.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numpy as np
import pytest

from python_tsp.heuristics import solve_tsp_lin_kernighan
Expand All @@ -6,12 +7,12 @@
distance_matrix1,
distance_matrix2,
distance_matrix3,
optimal_permutation1,
optimal_permutation2,
optimal_permutation3,
optimal_distance1,
optimal_distance2,
optimal_distance3,
optimal_permutation1,
optimal_permutation2,
optimal_permutation3,
)


Expand Down Expand Up @@ -82,3 +83,18 @@ def test_lin_kernighan_log_file_is_created_if_required(tmp_path):

assert log_file.exists()
assert "Current value" in log_file.read_text()


@pytest.mark.parametrize(
"distance_matrix, xopt, fopt",
[
(np.array([[0, 5], [1, 0]]), [0, 1], 6),
(np.array([[0, 1], [1, 0]]), [0, 1], 2),
],
)
def test_lin_kernighan_handles_few_node_problems(distance_matrix, xopt, fopt):
"""It should handle problems with less than 4 nodes."""
x, fx = solve_tsp_lin_kernighan(distance_matrix=distance_matrix)

assert x == xopt
assert fx == fopt

0 comments on commit 4416f56

Please sign in to comment.