import copy from typing import Tuple import numpy as np import numpy.typing as npt from common import indexes_to_cities, plot_plan, read_data def hill_climbing(distances: npt.NDArray) -> Tuple[float, npt.NDArray]: """A simple hill climbing algorithm. The algorithm starts on a random permutation and attempts to improve the circuit by trying to switch neighboring elements. Each iteration tries to switch adjacent neighbors and sees which one yields the largest improvement. Args: distances npt.NDArray: A matrix containing the distances between cities. Returns: Tuple[float, npt.NDArray] A tuple containing the distance of the solution and the solution itself. """ size: int = len(distances) # The size of the permutation array perm: npt.NDArray = np.arange(size) # Create an array from 0..size np.random.shuffle(perm) # Get random permutation # Get the distance of the random permutation current_distance: float = np.sum( [distances[perm[i - 1], perm[i]] for i in range(size)] ) found_improvement: bool = True while found_improvement: found_improvement = False # Assume we haven't found an improvement tmp_distance: float = current_distance # Try to find an improvement for i in range(size): perm[[i - 1, i]] = perm[[i, i - 1]] # Swap i - 1 and i tmp_distance: float = np.sum( [distances[perm[i - 1], perm[i]] for i in range(size)] ) if tmp_distance < current_distance: current_distance = tmp_distance found_improvement = True break perm[[i - 1, i]] = perm[[i, i - 1]] # Swap back i - 1 and i return (current_distance, perm) if __name__ == "__main__": cities, data = read_data("./european_cities.csv") distance, perm = hill_climbing(data[:10, :10]) plot_plan(indexes_to_cities(perm, cities))