cuGenOpt/benchmark/common/instances.py
2026-03-20 00:33:45 +08:00

136 lines
4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
标准实例解析器 — 从 TSPLIB / CVRPLIB 官方文件读取数据
数据文件位于 data/tsplib/ 和 data/cvrplib/
"""
import math
import os
DATA_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
TSPLIB_DIR = os.path.join(DATA_ROOT, "tsplib")
CVRPLIB_DIR = os.path.join(DATA_ROOT, "cvrplib")
def parse_tsp(filepath):
"""解析 TSPLIB .tsp 文件EUC_2D 格式)"""
meta = {}
coords = []
reading_coords = False
with open(filepath) as f:
for line in f:
line = line.strip()
if not line:
continue
if line == "NODE_COORD_SECTION":
reading_coords = True
continue
if line in ("EOF", "DISPLAY_DATA_SECTION"):
break
if reading_coords:
parts = line.split()
coords.append((float(parts[1]), float(parts[2])))
else:
if ":" in line:
key, val = line.split(":", 1)
meta[key.strip()] = val.strip()
n = int(meta.get("DIMENSION", len(coords)))
assert len(coords) == n, f"Expected {n} coords, got {len(coords)}"
return {"name": meta.get("NAME", ""), "n": n, "coords": coords}
def parse_vrp(filepath):
"""解析 CVRPLIB .vrp 文件"""
meta = {}
coords = []
demands = []
section = None
with open(filepath) as f:
for line in f:
line = line.strip()
if not line:
continue
if line == "NODE_COORD_SECTION":
section = "coord"
continue
elif line == "DEMAND_SECTION":
section = "demand"
continue
elif line in ("DEPOT_SECTION", "EOF"):
section = None
continue
if section == "coord":
parts = line.split()
coords.append((float(parts[1]), float(parts[2])))
elif section == "demand":
parts = line.split()
demands.append(int(parts[1]))
elif ":" in line:
key, val = line.split(":", 1)
meta[key.strip()] = val.strip()
n = int(meta.get("DIMENSION", len(coords)))
capacity = int(meta.get("CAPACITY", 0))
name = meta.get("NAME", "")
comment = meta.get("COMMENT", "")
optimal = 0
if "Optimal value:" in comment:
optimal = int(comment.split("Optimal value:")[-1].strip().rstrip(")"))
return {
"name": name,
"n": n,
"coords": coords,
"demands": demands,
"capacity": capacity,
"optimal": optimal,
}
def euc2d_dist_matrix(coords):
"""EUC_2D 距离矩阵(四舍五入到整数,与 TSPLIB 标准一致)"""
n = len(coords)
dist = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(n):
dx = coords[i][0] - coords[j][0]
dy = coords[i][1] - coords[j][1]
dist[i][j] = round(math.sqrt(dx * dx + dy * dy))
return dist
# ============================================================
# 预定义实例列表(文件名 → 已知最优)
# ============================================================
TSP_INSTANCES = [
{"file": "eil51.tsp", "optimal": 426},
{"file": "eil76.tsp", "optimal": 538},
{"file": "kroA100.tsp", "optimal": 21282},
{"file": "ch150.tsp", "optimal": 6528},
{"file": "tsp225.tsp", "optimal": 3916},
{"file": "lin318.tsp", "optimal": 42029},
{"file": "pcb442.tsp", "optimal": 50778},
]
VRP_INSTANCES = [
{"file": "A-n32-k5.vrp", "optimal": 784, "n_vehicles": 5},
]
def load_tsp(entry):
"""加载一个 TSP 实例"""
data = parse_tsp(os.path.join(TSPLIB_DIR, entry["file"]))
data["optimal"] = entry["optimal"]
return data
def load_vrp(entry):
"""加载一个 VRP 实例"""
data = parse_vrp(os.path.join(CVRPLIB_DIR, entry["file"]))
data["optimal"] = entry["optimal"]
data["n_vehicles"] = entry["n_vehicles"]
return data