-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Write instances and solutions (#109)
- Loading branch information
Showing
8 changed files
with
443 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import numpy as np | ||
from numpy.testing import assert_equal | ||
from pytest import mark | ||
|
||
from vrplib import write_instance | ||
|
||
|
||
@mark.parametrize( | ||
"key, value, desired", | ||
( | ||
["name", "Instance", "name: Instance"], # string | ||
["DIMENSION", 100, "DIMENSION: 100"], # int | ||
["VEHICLES", -10, "VEHICLES: -10"], # negative | ||
["CAPACITY", 10.5, "CAPACITY: 10.5"], # float | ||
["EMPTY", "", "EMPTY: "], # empty | ||
), | ||
) | ||
def test_specifications(tmp_path, key, value, desired): | ||
""" | ||
Tests that key-value pairs where values are floats or strings are | ||
formatted as specifications. | ||
""" | ||
name = "specifications" | ||
instance = {key: value} | ||
write_instance(tmp_path / name, instance) | ||
|
||
desired = "\n".join([desired, "EOF", ""]) | ||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), desired) | ||
|
||
|
||
@mark.parametrize( | ||
"key, value, desired", | ||
( | ||
# 1-dimensional list | ||
["X_SECTION", [0, 10], "\n".join(["X_SECTION", "1\t0", "2\t10"])], | ||
# 1-dimensional list with mixed int and float values | ||
["X_SECTION", [0, 10.5], "\n".join(["X_SECTION", "1\t0", "2\t10.5"])], | ||
# 1-dimensional list empty | ||
["X_SECTION", [], "\n".join(["X_SECTION"])], | ||
# 2-dimensional numpy array | ||
[ | ||
"Y_SECTION", | ||
np.array([[0, 0], [1, 1]]), | ||
"\n".join(["Y_SECTION", "1\t0\t0", "2\t1\t1"]), | ||
], | ||
# 2-dimensional list empty | ||
["Y_SECTION", [[]], "\n".join(["Y_SECTION", "1\t"])], | ||
# 2-dimensional array with different row lengths | ||
# NOTE: This is currently an invalid VRPLIB format, see | ||
# https://github.com/leonlan/VRPLIB/issues/108. | ||
[ | ||
"DATA_SECTION", | ||
[[1], [3, 4]], | ||
"\n".join(["DATA_SECTION", "1\t1", "2\t3\t4"]), | ||
], | ||
), | ||
) | ||
def test_sections(tmp_path, key, value, desired): | ||
""" | ||
Tests that key-value pairs where values are lists are formatted as | ||
sections. | ||
""" | ||
name = "sections" | ||
instance = {key: value} | ||
write_instance(tmp_path / name, instance) | ||
|
||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), "\n".join([desired, "EOF", ""])) | ||
|
||
|
||
def test_no_indices_depot_and_edge_weight_section(tmp_path): | ||
""" | ||
Tests that indices are not included when formatting depot and edge weight | ||
section. | ||
""" | ||
# Let's first test the depot section. | ||
name = "depot" | ||
instance = {"DEPOT_SECTION": [1, 2]} | ||
write_instance(tmp_path / name, instance) | ||
|
||
desired = "\n".join(["DEPOT_SECTION", "1", "2", "EOF", ""]) | ||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), desired) | ||
|
||
# Now let's test the edge weight section. | ||
name = "edge_weight" | ||
instance = { | ||
"EDGE_WEIGHT_SECTION": [ | ||
[1, 1, 2], | ||
[1, 0, 3], | ||
[1, 3, 0], | ||
] | ||
} | ||
write_instance(tmp_path / name, instance) | ||
|
||
desired = "\n".join( | ||
[ | ||
"EDGE_WEIGHT_SECTION", | ||
"1\t1\t2", | ||
"1\t0\t3", | ||
"1\t3\t0", | ||
"EOF", | ||
"", | ||
] | ||
) | ||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), desired) | ||
|
||
|
||
def test_small_instance_example(tmp_path): | ||
""" | ||
Tests if writing a small instance yields the correct result. | ||
""" | ||
name = "C101" | ||
instance = { | ||
"NAME": name, | ||
"TYPE": "VRPTW", | ||
"DIMENSION": 4, | ||
"CAPACITY": 200, | ||
"NODE_COORD_SECTION": [ | ||
[40, 50], | ||
[45, 68], | ||
[45, 70], | ||
[42, 66], | ||
], | ||
"DEMAND_SECTION": [0, 10, 30, 10], | ||
"DEPOT_SECTION": [1], | ||
} | ||
|
||
write_instance(tmp_path / name, instance) | ||
|
||
desired = "\n".join( | ||
[ | ||
"NAME: C101", | ||
"TYPE: VRPTW", | ||
"DIMENSION: 4", | ||
"CAPACITY: 200", | ||
"NODE_COORD_SECTION", | ||
"1\t40\t50", | ||
"2\t45\t68", | ||
"3\t45\t70", | ||
"4\t42\t66", | ||
"DEMAND_SECTION", | ||
"1\t0", | ||
"2\t10", | ||
"3\t30", | ||
"4\t10", | ||
"DEPOT_SECTION", | ||
"1", | ||
"EOF", | ||
"", | ||
] | ||
) | ||
|
||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), desired) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
from numpy.testing import assert_equal, assert_raises | ||
from pytest import mark | ||
|
||
from vrplib import write_solution | ||
|
||
|
||
@mark.parametrize( | ||
"routes, desired", | ||
[ | ||
([[1, 2]], "Route #1: 1 2"), | ||
([[1, 2], [42, 9]], "Route #1: 1 2\nRoute #2: 42 9"), | ||
], | ||
) | ||
def test_write_routes(tmp_path, routes, desired): | ||
""" | ||
Tests the writing of a solution with routes. | ||
""" | ||
name = "test.sol" | ||
write_solution(tmp_path / name, routes) | ||
|
||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), desired + "\n") | ||
|
||
|
||
def test_raise_empty_routes(tmp_path): | ||
""" | ||
Tests that an error is raised if a route is empty. | ||
""" | ||
name = "test.sol" | ||
|
||
with assert_raises(ValueError): | ||
write_solution(tmp_path / name, [[]]) | ||
|
||
with assert_raises(ValueError): | ||
write_solution(tmp_path / name, [[1], []]) | ||
|
||
|
||
@mark.parametrize( | ||
"data, desired", | ||
[ | ||
({"Cost": 100}, "Cost: 100"), # int | ||
({"Time": 123.45}, "Time: 123.45"), # float | ||
({"Distance": -1}, "Distance: -1"), # negative int | ||
({"name": "test.sol"}, "name: test.sol"), # string | ||
({"Vehicle types": [1, 2, 3]}, "Vehicle types: [1, 2, 3]"), # list | ||
({"Vehicle types": (1, 3)}, "Vehicle types: (1, 3)"), # tuple | ||
], | ||
) | ||
def test_format_other_data(tmp_path, data, desired): | ||
name = "test.sol" | ||
routes = [[1]] | ||
write_solution(tmp_path / name, routes, data) | ||
|
||
with open(tmp_path / name, "r") as fh: | ||
text = "Route #1: 1" + "\n" + desired + "\n" | ||
assert_equal(fh.read(), text) | ||
|
||
|
||
def test_small_example(tmp_path): | ||
""" | ||
Tests the writing of a small example. | ||
""" | ||
name = "test.sol" | ||
routes = [[1, 2], [3, 4], [5]] | ||
data = {"Cost": 100, "Time": 123.45, "name": name} | ||
|
||
write_solution(tmp_path / name, routes, data) | ||
|
||
desired = "\n".join( | ||
[ | ||
"Route #1: 1 2", | ||
"Route #2: 3 4", | ||
"Route #3: 5", | ||
"Cost: 100", | ||
"Time: 123.45", | ||
"name: test.sol", | ||
"", | ||
] | ||
) | ||
|
||
with open(tmp_path / name, "r") as fh: | ||
assert_equal(fh.read(), desired) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from .download import download_instance, download_solution, list_names | ||
from .read import read_instance, read_solution | ||
from .write import write_instance, write_solution |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .write_instance import write_instance | ||
from .write_solution import write_solution |
Oops, something went wrong.