master > master: tsp
This commit is contained in:
parent
5e92cd1fd4
commit
00e5432b6c
@ -6,6 +6,7 @@
|
|||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
import math;
|
import math;
|
||||||
|
import numpy as np;
|
||||||
import random;
|
import random;
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -14,5 +15,6 @@ import random;
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'math',
|
'math',
|
||||||
|
'np',
|
||||||
'random',
|
'random',
|
||||||
];
|
];
|
||||||
|
@ -17,6 +17,7 @@ from typing import Tuple;
|
|||||||
from typing import Type;
|
from typing import Type;
|
||||||
from typing import TypeVar;
|
from typing import TypeVar;
|
||||||
from typing import Union;
|
from typing import Union;
|
||||||
|
from nptyping import NDArray;
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
# EXPORTS
|
# EXPORTS
|
||||||
@ -34,4 +35,5 @@ __all__ = [
|
|||||||
'Type',
|
'Type',
|
||||||
'TypeVar',
|
'TypeVar',
|
||||||
'Union',
|
'Union',
|
||||||
|
'NDArray',
|
||||||
];
|
];
|
||||||
|
@ -12,8 +12,10 @@ os.chdir(os.path.join(os.path.dirname(__file__), '..'));
|
|||||||
sys.path.insert(0, os.getcwd());
|
sys.path.insert(0, os.getcwd());
|
||||||
|
|
||||||
from src.core.log import *;
|
from src.core.log import *;
|
||||||
|
from src.local.maths import *;
|
||||||
from src.graphs.graph import *;
|
from src.graphs.graph import *;
|
||||||
from src.graphs.tarjan import *;
|
from src.graphs.tarjan import *;
|
||||||
|
from src.travel.naive import *;
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
# GLOBAL CONSTANTS/VARIABLES
|
# GLOBAL CONSTANTS/VARIABLES
|
||||||
@ -26,28 +28,17 @@ from src.graphs.tarjan import *;
|
|||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
def enter():
|
def enter():
|
||||||
## Beispiel aus Seminarblatt 1
|
## Beispiel aus Seminarblatt 8
|
||||||
nodes = [1,2,3,4,5,6,7,8];
|
tsp_naive_algorithm(
|
||||||
edges = [
|
dist = np.asarray([
|
||||||
(1,2),
|
[0, 7, 2, 5],
|
||||||
(1,3),
|
[7, 0, 5, 6],
|
||||||
(2,4),
|
[2, 5, 0, 5],
|
||||||
(2,5),
|
[2, 7, 4, 0],
|
||||||
(3,5),
|
], dtype=float),
|
||||||
(3,6),
|
optimise=max,
|
||||||
(3,8),
|
verbose=True,
|
||||||
(4,5),
|
);
|
||||||
(4,7),
|
|
||||||
(5,1),
|
|
||||||
(5,8),
|
|
||||||
(6,8),
|
|
||||||
(7,8),
|
|
||||||
(8,6),
|
|
||||||
];
|
|
||||||
G = Graph(nodes=nodes, edges=edges);
|
|
||||||
components = tarjan_algorithm(G, debug=True);
|
|
||||||
for component in components:
|
|
||||||
log_debug(component);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
75
code/python/src/travel/naive.py
Normal file
75
code/python/src/travel/naive.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# IMPORTS
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
from __future__ import annotations;
|
||||||
|
from src.local.typing import *;
|
||||||
|
from src.local.maths import *;
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# EXPORTS
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'tsp_naive_algorithm',
|
||||||
|
];
|
||||||
|
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
# METHOD tsp_naive_algorithm
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
def tsp_naive_algorithm(
|
||||||
|
dist: 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]));
|
||||||
|
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({i}, {list(S)}) = {value}');
|
||||||
|
if len(paths) == 1:
|
||||||
|
print(f'optimal path: {" -> ".join(map(str, paths[0]))}');
|
||||||
|
else:
|
||||||
|
print('optimal paths:');
|
||||||
|
for path in paths:
|
||||||
|
print(f'* {" -> ".join(map(str, path))}');
|
||||||
|
print('');
|
||||||
|
return;
|
@ -6,17 +6,8 @@
|
|||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
from unittest import TestCase;
|
from unittest import TestCase;
|
||||||
from pytest import mark;
|
|
||||||
from pytest import fixture;
|
from pytest import fixture;
|
||||||
|
|
||||||
from tests.core.log import *;
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# CONSTANTS
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
# FIXTURES
|
# FIXTURES
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@ -24,3 +15,11 @@ from tests.core.log import *;
|
|||||||
@fixture(scope='module')
|
@fixture(scope='module')
|
||||||
def test():
|
def test():
|
||||||
return TestCase();
|
return TestCase();
|
||||||
|
|
||||||
|
@fixture(scope='module')
|
||||||
|
def debug():
|
||||||
|
def log(*lines: str):
|
||||||
|
with open('logs/debug.log', 'a') as fp:
|
||||||
|
for line in lines:
|
||||||
|
print(line, end='\n', file=fp);
|
||||||
|
return log;
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# IMPORTS
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
# METHODS - logging
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
def log(*lines: str):
|
|
||||||
with open('logs/debug.log', 'a') as fp:
|
|
||||||
for line in lines:
|
|
||||||
print(line, end='\n', file=fp);
|
|
@ -9,8 +9,6 @@ from unittest import TestCase;
|
|||||||
from pytest import mark;
|
from pytest import mark;
|
||||||
from pytest import fixture;
|
from pytest import fixture;
|
||||||
|
|
||||||
from tests.core.log import *;
|
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
# CONSTANTS
|
# CONSTANTS
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
# IMPORTS
|
# IMPORTS
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
from contextlib import nullcontext as does_not_raise
|
import pytest;
|
||||||
from collections import Counter;
|
|
||||||
from pytest import mark;
|
from pytest import mark;
|
||||||
from pytest import fixture;
|
from pytest import fixture;
|
||||||
from pytest import lazy_fixture;
|
from pytest import lazy_fixture;
|
||||||
from unittest import TestCase;
|
from unittest import TestCase;
|
||||||
|
from unittest.mock import patch;
|
||||||
|
|
||||||
from src.local.typing import *;
|
from src.local.typing import *;
|
||||||
from src.graphs.graph import *;
|
from src.graphs.graph import *;
|
||||||
@ -73,6 +73,13 @@ def test_tarjan(test, G, expected):
|
|||||||
components = tarjan_algorithm(G, False);
|
components = tarjan_algorithm(G, False);
|
||||||
assert_components_eq(test, components, expected);
|
assert_components_eq(test, components, expected);
|
||||||
|
|
||||||
|
@patch(f'{__name__}.tarjan_algorithm', lambda *_: [])
|
||||||
|
@mark.parametrize(('G', 'expected'), [ (lazy_fixture('graph1'), [[1], [3], [2,4]])])
|
||||||
|
@mark.usefixtures('test')
|
||||||
|
def test_failable_tarjan(test, G, expected):
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
test_tarjan(test, G, expected);
|
||||||
|
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
# AUXILIARY METHODS
|
# AUXILIARY METHODS
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Loading…
x
Reference in New Issue
Block a user