Improve the code.

- Add a docstring.
- Add type hinting.
- Change algorithm from steepest ascent to simple hill climbing.
This commit is contained in:
Cory Balaton 2024-10-01 19:20:34 +02:00
parent 667c19ecc3
commit a060f93554
Signed by: coryab
GPG Key ID: F7562F0EC4E4A61B

View File

@ -1,53 +1,66 @@
import copy
from typing import Tuple from typing import Tuple
import numpy as np import numpy as np
import numpy.typing as npt import numpy.typing as npt
import copy
from common import plot_plan, read_data from common import indexes_to_cities, plot_plan, read_data
original_perm = None
def hill_climbing(distances: npt.NDArray) -> Tuple[float, npt.NDArray]: def hill_climbing(distances: npt.NDArray) -> Tuple[float, npt.NDArray]:
size = len(distances) """A simple hill climbing algorithm.
perm = np.arange(size)
np.random.shuffle(perm) 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
print(perm)
global original_perm
original_perm = copy.deepcopy(perm)
current_route: float = np.sum([distances[perm[i - 1], perm[i]] for i in range(size)])
found_improvement = True
while found_improvement: while found_improvement:
found_improvement = False
tmp_improvement: float = current_route found_improvement = False # Assume we haven't found an improvement
improvement_index: int = -1 tmp_distance: float = current_distance
# Try to find an improvement
for i in range(size): for i in range(size):
perm[i - 1], perm[i] = perm[i], perm[i - 1] perm[[i - 1, i]] = perm[[i, i - 1]] # Swap i - 1 and i
tmp_route: float = np.sum([distances[perm[i - 1], perm[i]] for i in range(size)])
if tmp_route < tmp_improvement:
tmp_improvement = tmp_route
improvement_index = i
found_improvement = True
perm[i - 1], perm[i] = perm[i], perm[i - 1] tmp_distance: float = np.sum(
[distances[perm[i - 1], perm[i]] for i in range(size)]
if found_improvement:
current_route = tmp_improvement
perm[improvement_index - 1], perm[improvement_index] = (
perm[improvement_index],
perm[improvement_index - 1],
) )
print(perm) if tmp_distance < current_distance:
current_distance = tmp_distance
found_improvement = True
break
return (current_route, perm) perm[[i - 1, i]] = perm[[i, i - 1]] # Swap back i - 1 and i
return (current_distance, perm)
if __name__ == "__main__": if __name__ == "__main__":
cities, data = read_data("./european_cities.csv") cities, data = read_data("./european_cities.csv")
distance, perm = hill_climbing(data[:10,:10]) distance, perm = hill_climbing(data[:10, :10])
plot_plan(list(map(lambda i: cities[i], list(perm))))
plot_plan(list(map(lambda i: cities[i], list(original_perm))))
plot_plan(indexes_to_cities(perm, cities))