From 80de85d0843d99f3ce1ced4b0158d5ebbcddc5b4 Mon Sep 17 00:00:00 2001 From: Robert Grant Date: Mon, 30 Mar 2020 20:25:47 -0700 Subject: [PATCH] Fixes #11 --- tests/data/testfixture.py | 0 tests/test_distances.py | 14 +++++++++++++- tsplib95/distances.py | 6 +++--- tsplib95/models.py | 4 ++++ tsplib95/utils.py | 9 +++++++-- 5 files changed, 27 insertions(+), 6 deletions(-) delete mode 100644 tests/data/testfixture.py diff --git a/tests/data/testfixture.py b/tests/data/testfixture.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_distances.py b/tests/test_distances.py index cf78d60..ec761b2 100644 --- a/tests/test_distances.py +++ b/tests/test_distances.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import pytest +from tsplib95 import models from tsplib95 import distances @@ -56,7 +57,7 @@ def test_maximum(start, end, dist, exc): ((3, 4), (3, 4), 1, None), ((0, 0), (3, 4), 557, None), ((3, 4), (0, 0), 557, None), - ((-3, -4), (3, 4), 1218, None), + ((-3, -4), (3, 4), 1113, None), ((0, 1), (0, 1, 2), None, ValueError), ((0, 1, 2), (0, 1), None, ValueError), ]) @@ -66,3 +67,14 @@ def test_geographical(start, end, dist, exc): distances.geographical(start, end) else: assert distances.geographical(start, end) == dist + + +@pytest.mark.parametrize('pfile,answer', [ + ('data/pcb442.tsp', 221440), + ('data/gr666.tsp', 423710), + ('data/att532.tsp', 309636), +]) +def test_verifcation_problems(read_problem_text, pfile, answer): + problem_text = read_problem_text(pfile) + problem = models.StandardProblem.parse(problem_text) + assert problem.trace_canonical_tour() == answer diff --git a/tsplib95/distances.py b/tsplib95/distances.py index c262bdf..d181a8c 100644 --- a/tsplib95/distances.py +++ b/tsplib95/distances.py @@ -74,7 +74,7 @@ def geographical(start, end, round=utils.nint, radius=6378.388): q3 = math.cos(start.lat + end.lat) distance = radius * math.acos(0.5 * ((1 + q1) * q2 - (1 - q1) * q3)) + 1 - return round(distance) + return int(distance) def pseudo_euclidean(start, end, round=utils.nint): @@ -127,8 +127,8 @@ def xray(start, end, sx=1, sy=1, sz=1, round=utils.icost): 'MAN_2D': manhattan, 'MAN_3D': manhattan, 'CEIL_2D': functools.partial(euclidean, round=math.ceil), - 'GEO': euclidean, - 'ATT': euclidean, + 'GEO': geographical, + 'ATT': pseudo_euclidean, 'XRAY1': xray, 'XRAY2': functools.partial(xray, sx=1.25, sy=1.5, sz=1.15), } diff --git a/tsplib95/models.py b/tsplib95/models.py index ee7d839..ae7bdf4 100644 --- a/tsplib95/models.py +++ b/tsplib95/models.py @@ -254,6 +254,10 @@ def trace_tours(self, solution): solutions.append(weight) return solutions + def trace_canonical_tour(self): + canonical_edges = utils.pairwise(self.get_nodes()) + return sum(self.wfunc(i, j) for i, j in canonical_edges) + def get_nodes(self): """Return an iterator over the nodes. diff --git a/tsplib95/utils.py b/tsplib95/utils.py index a45ea68..85ec590 100644 --- a/tsplib95/utils.py +++ b/tsplib95/utils.py @@ -9,7 +9,7 @@ def parse_degrees(coord): :return: real degrees :rtype: float """ - degrees = nint(coord) + degrees = int(coord) minutes = coord - degrees return degrees + minutes * 5 / 3 @@ -58,9 +58,14 @@ def integer_sum(n, m=None): def pairwise(indexes): + # double list double in case indexes is an iterator starts = list(indexes) - ends = list(indexes) + ends = list(starts) + + # shift the ends by one, and make it circular ends += [ends.pop(0)] + + # pair up the neighbors return zip(starts, ends)