Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions scripts/spaceship_reorder_by_tsp_lkh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Install [LKH-3](http://webhotel4.ruc.dk/~keld/research/LKH-3/)
# This script uses "./LKH-3.0.10/LKH".

import argparse
import math
import subprocess


def reorder(points):
par_filename = "spaceship_tsp.tmp.par"
tsp_filename = "spaceship_tsp.tmp.tsp"
out_filename = "spaceship_tsp.tmp.out"

nodes = [(0, 0)] + points + [None, None]
dim = len(nodes)
start_node_id = 0 # 始点
sink_node_id = dim - 2 # 終点
dummy_node_id = dim - 1 # 終点と始点を繋いでサイクルにするためのダミーのノード

def dist(i, j):
# ダミーのノードは始点と終点にはコスト0で繋がっているが他には繋がっていない
if i == dummy_node_id:
if j == start_node_id or j == sink_node_id:
return 0
else:
return None
if j == dummy_node_id:
if i == start_node_id or i == sink_node_id:
return 0
else:
return None
# 終点は始点とダミー以外の全てのノードにコスト0で繋がっている
if i == sink_node_id:
if j == start_node_id:
return None
else:
return 0
if j == sink_node_id:
if i == start_node_id:
return None
else:
return 0

p1 = nodes[i]
p2 = nodes[j]
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)

edge_weights = [[dist(i, j) for j in range(i)] for i in range(len(nodes))]

precision = 100
int_max = 2**31

# LKH は重みは整数である必要があり、
# また w <= <= int_max // 2 // precision を満たす必要があるので、
# 適当にスケーリング。
#
# 後述の inf と他の値に差が出るように 10 倍だけ余裕を持っておく
max_w = max(w for ws in edge_weights for w in ws if w is not None)
s = 1
if round(10 * s * max_w) <= int_max // 2 // precision // 10:
while round(10 * s * max_w) <= int_max // 2 // precision // 10:
s *= 10
else:
while round(10 * s * max_w) > int_max // 2 // precision // 10:
s /= 10
edge_weights = [
[None if w is None else round(s * w) for w in ws] for ws in edge_weights
]
for ws in edge_weights:
for w in ws:
if w is not None:
assert w <= int_max // 2 // precision // 10

# EDGE_DATA_FORMAT を指定するとうまくいかないので、
# その代わりにエッジがない場所には大きな値を入れておく。
inf = int_max // 2 // precision

with open(tsp_filename, "w") as f:
print("NAME: hoge", file=f)
print("TYPE: TSP", file=f)
print(f"DIMENSION: {dim}", file=f)
print(f"EDGE_WEIGHT_TYPE: EXPLICIT", file=f)
print(f"EDGE_WEIGHT_FORMAT: LOWER_ROW", file=f)
# print("EDGE_DATA_FORMAT: ADJ_LIST", file=f)
# print("EDGE_DATA_SECTION:", file=f)
# for i, ws in enumerate(edge_weights):
# print(' '.join(map(str, [i+1] + [j+1 for (j, w) in enumerate(ws) if w is not None] + [-1])), file=f)
# print(f"-1", file=f)
print(f"EDGE_WEIGHT_SECTION:", file=f)
for ws in edge_weights:
print(" ".join(map(str, [inf if w is None else w for w in ws])), file=f)
print(f"EOF", file=f)

with open(par_filename, "w") as f:
print(f"PROBLEM_FILE = {tsp_filename}", file=f)
print(f"OUTPUT_TOUR_FILE = {out_filename}", file=f)
print("MOVE_TYPE = 5", file=f)
print("PATCHING_C = 3", file=f)
print("PATCHING_A = 2", file=f)
print("RUNS = 10", file=f)

subprocess.run(
[
"./LKH-3.0.10/LKH",
par_filename,
],
text=True,
check=True,
)

tour = []
in_tour_section = False
with open(out_filename) as f:
for line in f:
if in_tour_section:
if int(line) == -1:
break
else:
tour.append(int(line))
elif line.startswith("TOUR_SECTION"):
in_tour_section = True
assert len(tour) == dim

# 1-origin to 0-origin
tour = [i - 1 for i in tour]

start_node_index = tour.index(start_node_id)
tour = tour[start_node_index:] + tour[:start_node_index]
assert tour[0] == start_node_id

if tour[-1] == dummy_node_id:
assert tour[-2] == sink_node_id
tour.pop()
tour.pop()
elif tour[1] == dummy_node_id:
assert tour[2] == sink_node_id
tour = [start_node_id] + list(reversed(tour[3:]))
else:
assert False

return [points[i - 1] for i in tour[1:]]


parser = argparse.ArgumentParser()
parser.add_argument("file", type=str, metavar="FILE", help="spaceship problem file")
parser.add_argument(
"--output", "-o", type=str, metavar="FILE", required=True, help="output png file"
)
args = parser.parse_args()

points = []
with open(args.file) as f:
for line in f:
x, y = line.split()
points.append((int(x), int(y)))

points2 = reorder(points)
with open(args.output, "w") as f:
for p in points2:
print(f"{p[0]} {p[1]}", file=f)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions solutions/spaceship1/prob_reordered_by_tsp_lkh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
1 -1
1 -3
2 -5
2 -8
3 -10
Binary file added solutions/spaceship1/sol_reordered_by_tsp_lkh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions solutions/spaceship1/sol_reordered_by_tsp_lkh.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
34826725582672
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 100 additions & 0 deletions solutions/spaceship10/prob_reordered_by_tsp_lkh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
1 -2
2 -8
3 -16
-3 -22
-9 -22
-8 -27
-9 -33
-9 -38
-13 -43
-24 -43
-31 -50
-38 -56
-41 -60
-50 -60
-56 -70
-67 -73
-74 -79
-86 -91
-95 -97
-109 -112
-127 -122
-139 -130
-156 -139
-169 -146
-189 -153
-210 -167
-227 -171
-246 -179
-262 -190
-281 -204
-298 -219
-316 -229
-335 -243
-353 -257
-373 -265
-394 -277
-421 -293
-442 -300
-469 -317
-497 -328
-521 -340
-546 -350
-570 -361
-592 -369
-615 -377
-631 -388
-661 -403
-684 -405
-705 -420
-727 -429
-755 -440
-780 -452
-805 -459
-831 -470
-854 -478
-870 -482
-890 -495
-905 -501
-921 -514
-938 -528
-948 -542
-963 -549
-975 -562
-990 -572
-1000 -579
-1014 -590
-1018 -598
-1030 -605
-1038 -606
-1048 -609
-1055 -607
-1060 -606
-1069 -610
-1078 -603
-1084 -603
-1090 -604
-1095 -602
-1096 -604
-1101 -600
-1106 -603
-1107 -600
-1114 -598
-1113 -596
-1106 -587
-1109 -580
-1112 -574
-1117 -568
-1119 -562
-1128 -560
-1134 -560
-1145 -551
-1157 -548
-1171 -544
-1189 -535
-1201 -535
-1212 -537
-1228 -536
-1242 -531
-1258 -522
-1272 -526
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions solutions/spaceship10/sol_reordered_by_tsp_lkh.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3723755823485582176591765564337821955822858218591746655641295673176583725673745655641355949244829556412959111959591185683711385686731448658386411686837115955929411956829411856829564111968568371459286564115868385641156865837112868658371129559591145865929411286865837112868659114856829564111995592941115959592864117668295641115959568294114595682956411198658386411468592956411468658386411495929564114959295564115686583711185686838641719565655641119658683711495683864114595682956411198568386411765838656411459568386411495929556414592955641128685929411868386411295958371129586591128658673147682956411386867314495592941286583711658659116946821476928641865564158385647292647356415592947826537165564195564738343737766191169197628419256493796425197426197264387166197346284183556446556477635537443835647462835647752653834446565641739556471565655647732835647753562834146829564
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading