-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconcorde_baseline.py
63 lines (49 loc) · 1.85 KB
/
concorde_baseline.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import numpy as np
import torch
import pickle
import os
import argparse
from concorde.tsp import TSPSolver
from utils.local_search import tsp_length_batch
PRECISION_SCALAR = 100_000 # Concorde rounds edge weights
EDGE_WEIGHT_TYPE = "EUC_2D"
if __name__ == "__main__":
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument("--data_path", type=str, default=None, help="Filename of the dataset to evaluate")
opts = parser.parse_args()
assert opts.data_path is not None, "Need to specify data path"
# Read in dataset
name = os.path.splitext(os.path.basename(opts.data_path))[0]
with open(opts.data_path, "rb") as f:
dataset = pickle.load(f)
positions = np.array(dataset)
# Solve each instance
M, N, _ = positions.shape
tours = np.zeros((M, N))
for i in range(M):
solver = TSPSolver.from_data(
positions[i,:,0] * PRECISION_SCALAR,
positions[i,:,1] * PRECISION_SCALAR,
norm=EDGE_WEIGHT_TYPE
)
solution = solver.solve()
tours[i] = solution.tour
print(f"Finished instance {i+1}/{M} with cost {solution.optimal_value/PRECISION_SCALAR}")
del solver
del solution
costs = tsp_length_batch(
torch.from_numpy(positions),
torch.from_numpy(tours).long()
)
# Write to output
result_dir = f"results/tsp/{name}"
os.makedirs(result_dir, exist_ok=True)
costs = costs.numpy().tolist()
with open(f"{result_dir}/concorde_costs.pkl", "wb") as f:
pickle.dump(costs, f, pickle.HIGHEST_PROTOCOL)
print(f"Saved concorde costs to {result_dir}/concorde_costs.pkl")
tours = tours.tolist()
with open(f"{result_dir}/concorde_tours.pkl", "wb") as f:
pickle.dump(tours, f, pickle.HIGHEST_PROTOCOL)
print(f"Saved concorde tours to {result_dir}/concorde_tours.pkl")