ads2_2022/code/python/src/algorithms/tsp/algorithms.py

76 lines
3.0 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.thirdparty.types import *;
from src.thirdparty.maths import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'tsp_algorithm',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHOD tsp_algorithm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def tsp_algorithm(
dist: np.ndarray, # NDArray[(Any, Any), float],
optimise = min,
verbose: bool = False,
) -> tuple[float, list[list[int]]]:
m, n = dist.shape[:2];
assert m == n;
memory: Dict[tuple[int, tuple], tuple[float, list[list[int]]]] = dict();
def g(i: int, S: list[int]) -> tuple[float, list[list[int]]]:
# wenn g bereits für den Input definiert ist, gib diesen Wert zurück:
if (i, tuple(S)) not in memory.keys():
if len(S) == 0:
paths = [[i]] if i == 0 else [[i, 0]];
memory[(i, tuple(S))] = (dist[i,0], paths);
else:
values_and_paths = [ (j, *g(j, (*S[:index], *S[(index+1):]))) for index, j in enumerate(S) ];
# berechne d(i,j) + g(j, S \ {i}) for each j in S:
values_and_paths = [ (j, dist[i,j] + value, paths) for j, value, paths in values_and_paths];
value = optimise([value for _, value, _ in values_and_paths]);
paths = [];
for j, value_, paths_ in values_and_paths:
if value_ == value:
paths += [ [i, *path] for path in paths_ ];
memory[(i, tuple(S))] = (value, paths);
return memory[(i, tuple(S))];
# berechne g(0, {1,2,...,n-1}):
optimal_wert = g(0, [i for i in range(1,n)]);
if verbose:
display_computation(n, memory);
return optimal_wert, [];
def display_computation(n: int, memory: Dict[tuple[int, tuple], tuple[float, list[list[int]]]]):
keys = sorted(memory.keys(), key=lambda key: (len(key[1]), key[0], key[1]));
addone = lambda x: x + 1;
for k in range(0,n):
print(f'\x1b[4;1m|S| = {k}:\x1b[0m');
for (i, S) in keys:
if len(S) != k:
continue;
value, paths = memory[(i, S)];
print(f'g({addone(i)}, {list(map(addone, S))}) = {value}');
if len(paths) == 1:
print(f'optimal way: {" -> ".join(map(str, map(addone, paths[0])))}');
else:
print('optimal ways:');
for path in paths:
print(f'* {" -> ".join(map(str, map(addone, path)))}');
print('');
return;