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)
print(perm) The algorithm starts on a random permutation and attempts to improve
global original_perm the circuit by trying to switch neighboring elements. Each iteration
original_perm = copy.deepcopy(perm) tries to switch adjacent neighbors and sees which one yields the largest
current_route: float = np.sum([distances[perm[i - 1], perm[i]] for i in range(size)]) improvement.
found_improvement = True
while found_improvement:
found_improvement = False
tmp_improvement: float = current_route
improvement_index: int = -1
for i in range(size):
perm[i - 1], perm[i] = perm[i], perm[i - 1]
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] Args:
distances npt.NDArray: A matrix containing the distances between cities.
if found_improvement: Returns:
current_route = tmp_improvement Tuple[float, npt.NDArray] A tuple containing the distance of the
perm[improvement_index - 1], perm[improvement_index] = ( solution and the solution itself.
perm[improvement_index],
perm[improvement_index - 1], """
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)]
) )
print(perm) found_improvement: bool = True
return (current_route, perm) 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__": 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(indexes_to_cities(perm, cities))
plot_plan(list(map(lambda i: cities[i], list(original_perm))))