diff --git a/tests/parse/test_parse_solution.py b/tests/parse/test_parse_solution.py index 2248dafc..b959b411 100644 --- a/tests/parse/test_parse_solution.py +++ b/tests/parse/test_parse_solution.py @@ -24,6 +24,11 @@ "Route #1: 1 \n Route #2: 6\n ABCDE", {"routes": [[1], [6]]}, ), + ( + # Reload "|" character + "Route #1: 1 | 2 \n Route #2: 3", + {"routes": [[1, "|", 2], [3]]}, + ), ], ) def test_parse_solution(text, data): diff --git a/vrplib/parse/parse_solution.py b/vrplib/parse/parse_solution.py index 3cf384f9..a21c922a 100644 --- a/vrplib/parse/parse_solution.py +++ b/vrplib/parse/parse_solution.py @@ -7,8 +7,11 @@ def parse_solution(text: str) -> Solution: """ - Parses the text of a solution file formatted in VRPLIB style. A solution - consists of routes, which are indexed from 1 to n, and possibly other data. + Parses a VRPLIB-formatted solution text into a dictionary. + - Routes appear as "Route #n: node1 node2 node3..." where nodes can be: + * Integer indices (0-indexed, unlike 1-indexed instance data) + * String markers (e.g., "|" for reload depots). + - Additional metadata as key-value pairs (e.g., "Cost: 123.45") Parameters ---------- @@ -18,14 +21,17 @@ def parse_solution(text: str) -> Solution: Returns ------- dict - The soluion data. + The soluion data dictionary, containing: + - "routes": list of routes, each route being a list of nodes + - Additional metadata as key-value pairs from the solution """ solution: Solution = {"routes": []} for line in text2lines(text): if "Route" in line: - route = [int(idx) for idx in line.split(":")[1].split(" ") if idx] - solution["routes"].append(route) # type: ignore + raw_visits = line.split(":")[1].split() + visits = [int(val) if val.isdigit() else val for val in raw_visits] + solution["routes"].append(visits) # type: ignore elif ":" in line or " " in line: # Split at first colon or whitespace split_at = ":" if ":" in line else " " k, v = [word.strip() for word in line.split(split_at, 1)]