in4050-oblig1/hill_climbing.py
Cory Balaton a060f93554
Improve the code.
- Add a docstring.
- Add type hinting.
- Change algorithm from steepest ascent to simple hill climbing.
2024-10-01 19:20:34 +02:00

67 lines
1.9 KiB
Python

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))