Skip to content

Commit

Permalink
Merge pull request #126 from Kuifje02/non-elementary-routes
Browse files Browse the repository at this point in the history
Great job @torressa !!!
  • Loading branch information
Kuifje02 committed Apr 16, 2022
2 parents 667a118 + 7dd4d00 commit ff325cb
Show file tree
Hide file tree
Showing 20 changed files with 470 additions and 320 deletions.
4 changes: 3 additions & 1 deletion benchmarks/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from multiprocessing import Pool, cpu_count
from pathlib import Path
from typing import List, Dict, Union

from networkx import DiGraph

from benchmarks.augerat_dataset import AugeratDataSet
from benchmarks.solomon_dataset import SolomonDataSet
from benchmarks.utils.csv_table import CsvTable
Expand Down Expand Up @@ -202,7 +204,7 @@ def _run_single_problem(path_to_instance: Path, **kwargs):


def main():
""" Run parallel or series"""
"""Run parallel or series"""
if SERIES:
run_series()
else:
Expand Down
Binary file added benchmarks/tests/graph_issue101
Binary file not shown.
6 changes: 5 additions & 1 deletion benchmarks/tests/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
[pytest]
log_cli = 1
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format=%Y-%m-%d %H:%M:%S
python_files = test_*.py
#testpaths = tests/
filterwarnings =
ignore::DeprecationWarning
ignore::DeprecationWarning
50 changes: 12 additions & 38 deletions benchmarks/tests/test_cvrptw_solomon.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@


class TestsSolomon:

def setup(self):
"""
Solomon instance c101, 25 first nodes only including depot
"""
data = SolomonDataSet(path="benchmarks/data/cvrptw/",
instance_name="C101.txt",
n_vertices=25)
data = SolomonDataSet(
path="benchmarks/data/cvrptw/", instance_name="C101.txt", n_vertices=25
)
self.G = data.G
self.n_vertices = 25
self.prob = VehicleRoutingProblem(self.G,
load_capacity=data.max_load,
time_windows=True)
self.prob = VehicleRoutingProblem(
self.G, load_capacity=data.max_load, time_windows=True
)
initial_routes = [
["Source", 13, 17, 18, 19, 15, 16, 14, 12, 1, "Sink"],
["Source", 20, 24, 23, 22, 21, "Sink"],
Expand All @@ -26,7 +25,7 @@ def setup(self):
# Set repeating solver arguments
self.solver_args = {
"pricing_strategy": "BestPaths",
"initial_routes": initial_routes
"initial_routes": initial_routes,
}

def test_setup_instance_name(self):
Expand All @@ -40,43 +39,18 @@ def test_setup_nodes(self):
assert len(self.G.nodes()) == self.n_vertices + 1

def test_setup_edges(self):
assert len(
self.G.edges()) == self.n_vertices * (self.n_vertices - 1) + 1
assert len(self.G.edges()) == self.n_vertices * (self.n_vertices - 1) + 1

def test_subproblem_lp(self):
# benchmark result
# e.g., in Feillet et al. (2004)
self.prob.solve(**self.solver_args, cspy=False)
assert round(self.prob.best_value, -1) in [190, 200]

def test_schedule_lp(self):
'Tests whether final schedule is time-window feasible'
self.prob.solve(**self.solver_args, cspy=False)
# Check arrival times
for k1, v1 in self.prob.arrival_time.items():
for k2, v2 in v1.items():
assert (self.G.nodes[k2]["lower"] <= v2)
assert (v2 <= self.G.nodes[k2]["upper"])
# Check departure times
for k1, v1 in self.prob.departure_time.items():
for k2, v2 in v1.items():
assert (self.G.nodes[k2]["lower"] <= v2)
assert (v2 <= self.G.nodes[k2]["upper"])
self.prob.check_arrival_time()
self.prob.check_departure_time()

def test_subproblem_cspy(self):
self.prob.solve(**self.solver_args, cspy=True)
assert round(self.prob.best_value, -1) in [190, 200]

def test_schedule_cspy(self):
'Tests whether final schedule is time-window feasible'
self.prob.solve(**self.solver_args)
# Check departure times
for k1, v1 in self.prob.departure_time.items():
for k2, v2 in v1.items():
assert (self.G.nodes[k2]["lower"] <= v2)
assert (v2 <= self.G.nodes[k2]["upper"])
# Check arrival times
for k1, v1 in self.prob.arrival_time.items():
for k2, v2 in v1.items():
assert (self.G.nodes[k2]["lower"] <= v2)
assert (v2 <= self.G.nodes[k2]["upper"])
self.prob.check_arrival_time()
self.prob.check_departure_time()
64 changes: 52 additions & 12 deletions benchmarks/tests/test_cvrptw_solomon_range.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from pytest import fixture
from time import time
import csv

from vrpy import VehicleRoutingProblem

from benchmarks.solomon_dataset import SolomonDataSet

params = list(range(7, 10))
params = list(range(7, 70))


@fixture(
Expand All @@ -16,17 +18,55 @@ def n(request):
return request.param


REPS_LP = 1
REPS_CSPY = 10


def write_avg(n, times_cspy, iter_cspy, times_lp, iter_lp, name="cspy102fwdearly"):
def _avg(l):
return sum(l) / len(l)

with open(f"benchmarks/results/{name}.csv", "a", newline="") as f:
writer_object = csv.writer(f)
writer_object.writerow(
[n, _avg(times_cspy), _avg(iter_cspy), _avg(times_lp), _avg(iter_lp)]
)
f.close()


class TestsSolomon:
def test_subproblem(self, n):
data = SolomonDataSet(path="benchmarks/data/cvrptw/",
instance_name="C101.txt",
n_vertices=n)
data = SolomonDataSet(
path="benchmarks/data/cvrptw/", instance_name="C101.txt", n_vertices=n
)
self.G = data.G
self.prob = VehicleRoutingProblem(self.G,
load_capacity=data.max_load,
time_windows=True)
self.prob.solve(cspy=False)
best_value_lp = self.prob.best_value
self.prob.solve(cspy=True)
best_value_cspy = self.prob.best_value
assert int(best_value_lp) == int(best_value_cspy)
best_values_lp = None
lp_iter = []
times_lp = []
for r in range(REPS_LP):
prob = VehicleRoutingProblem(
self.G, load_capacity=data.max_load, time_windows=True
)
start = time()
prob.solve(cspy=False)
best_value_lp = prob.best_value
times_lp.append(time() - start)
lp_iter.append(prob._iteration)
del prob
best_values_cspy = []
times_cspy = []
iter_cspy = []
for r in range(REPS_CSPY):
prob = VehicleRoutingProblem(
self.G, load_capacity=data.max_load, time_windows=True
)
start = time()
prob.solve(cspy=True, pricing_strategy="Exact")
times_cspy.append(time() - start)
best_values_cspy.append(prob.best_value)
iter_cspy.append(prob._iteration)
prob.check_arrival_time()
prob.check_departure_time()
del prob
assert all(best_value_lp == val_cspy for val_cspy in best_values_cspy)
write_avg(n, times_cspy, iter_cspy, times_lp, lp_iter)
74 changes: 41 additions & 33 deletions benchmarks/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,35 +42,39 @@ def setup(self):
# Define VRP
self.prob = VehicleRoutingProblem(self.G)

def test_cvrp_dive(self):
def test_cvrp_dive_lp(self):
self.prob.load_capacity = 15
self.prob.solve(cspy=False, pricing_strategy="BestEdges1", dive=True)
sol_lp = self.prob.best_value
assert int(self.prob.best_value) == 6208

def test_cvrp_dive_cspy(self):
self.prob.load_capacity = 15
self.prob.solve(pricing_strategy="BestEdges1", dive=True)
sol_cspy = self.prob.best_value
assert int(sol_lp) == 6208
assert int(sol_cspy) == 6208
assert int(self.prob.best_value) == 6208

def test_vrptw_dive(self):
def test_vrptw_dive_lp(self):
self.prob.time_windows = True
self.prob.solve(cspy=False, dive=True)
sol_lp = self.prob.best_value
self.prob.solve(dive=True)
sol_cspy = self.prob.best_value
assert int(sol_lp) == 6528
assert int(sol_cspy) == 6528
assert int(self.prob.best_value) == 6528

def test_vrptw_dive_cspy(self):
self.prob.time_windows = True
self.prob.solve(cspy=True, dive=True)
assert int(self.prob.best_value) == 6528

def test_cvrpsdc_dive(self):
def test_cvrpsdc_dive_lp(self):
self.prob.load_capacity = 15
self.prob.distribution_collection = True
self.prob.solve(cspy=False, pricing_strategy="BestEdges1", dive=True)
sol_lp = self.prob.best_value
assert int(self.prob.best_value) == 6208

def test_cvrpsdc_dive_cspy(self):
self.prob.load_capacity = 15
self.prob.distribution_collection = True
self.prob.solve(pricing_strategy="BestEdges1", dive=True)
sol_cspy = self.prob.best_value
assert int(sol_lp) == 6208
assert int(sol_cspy) == 6208
assert int(self.prob.best_value) == 6208

def test_pdp_dive(self):
def test_pdp_dive_lp(self):
# Set demands and requests
for (u, v) in PICKUPS_DELIVERIES:
self.G.nodes[u]["request"] = v
Expand All @@ -83,35 +87,39 @@ def test_pdp_dive(self):
sol_lp = self.prob.best_value
assert int(sol_lp) == 5980

def test_cvrp(self):
def test_cvrp_lp(self):
self.prob.load_capacity = 15
self.prob.solve(cspy=False, pricing_strategy="BestEdges1")
sol_lp = self.prob.best_value
assert int(self.prob.best_value) == 6208

def test_cvrp_cspy(self):
self.prob.load_capacity = 15
self.prob.solve(pricing_strategy="BestEdges1")
sol_cspy = self.prob.best_value
assert int(sol_lp) == 6208
assert int(sol_cspy) == 6208
assert int(self.prob.best_value) == 6208

def test_vrptw(self):
def test_vrptw_lp(self):
self.prob.time_windows = True
self.prob.solve(cspy=False)
sol_lp = self.prob.best_value
assert int(self.prob.best_value) == 6528

def test_vrptw_cspy(self):
self.prob.time_windows = True
self.prob.solve()
sol_cspy = self.prob.best_value
assert int(sol_lp) == 6528
assert int(sol_cspy) == 6528
assert int(self.prob.best_value) == 6528

def test_cvrpsdc(self):
def test_cvrpsdc_lp(self):
self.prob.load_capacity = 15
self.prob.distribution_collection = True
self.prob.solve(cspy=False, pricing_strategy="BestEdges1")
sol_lp = self.prob.best_value
assert int(self.prob.best_value) == 6208

def test_cvrpsdc_cspy(self):
self.prob.load_capacity = 15
self.prob.distribution_collection = True
self.prob.solve(pricing_strategy="BestEdges1")
sol_cspy = self.prob.best_value
assert int(sol_lp) == 6208
assert int(sol_cspy) == 6208
assert int(self.prob.best_value) == 6208

def test_pdp(self):
def test_pdp_lp(self):
# Set demands and requests
for (u, v) in PICKUPS_DELIVERIES:
self.G.nodes[u]["request"] = v
Expand Down
19 changes: 19 additions & 0 deletions benchmarks/tests/test_issue101.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from networkx import DiGraph, read_gpickle
from vrpy import VehicleRoutingProblem


class TestIssue101_large:
def setup(self):
G = read_gpickle("benchmarks/tests/graph_issue101")
self.prob = VehicleRoutingProblem(G, load_capacity=80)
self.prob.time_windows = True

# def test_lp(self):
# self.prob.solve(cspy=False, solver="gurobi")
# self.prob.check_arrival_time()
# self.prob.check_departure_time()

def test_cspy(self):
self.prob.solve(pricing_strategy="Exact")
self.prob.check_arrival_time()
self.prob.check_departure_time()
12 changes: 11 additions & 1 deletion examples/pdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,18 @@
if __name__ == "__main__":

prob = VehicleRoutingProblem(G, load_capacity=6, pickup_delivery=True, num_stops=6)
prob.solve(cspy=False)
prob.solve(cspy=False, pricing_strategy="Exact")
print(prob.best_value)
print(prob.best_routes)
for (u, v) in PICKUPS_DELIVERIES:
found = False
for route in prob.best_routes.values():
if u in route and v in route:
found = True
break
if not found:
print((u, v), "Not present")
assert False

print(prob.node_load)
assert prob.best_value == 5980
7 changes: 6 additions & 1 deletion tests/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
[pytest]
log_cli = 1
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format=%Y-%m-%d %H:%M:%S

python_files = test_*.py
#testpaths = tests/
filterwarnings =
ignore::DeprecationWarning
ignore::DeprecationWarning
10 changes: 4 additions & 6 deletions tests/test_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ def test_consistency_parameters():
G = DiGraph()
G.add_edge("Source", "Sink", cost=1)
prob = VehicleRoutingProblem(G, pickup_delivery=True)
# pickup delivery requires cspy=False
with pytest.raises(NotImplementedError):
prob.solve()
# pickup delivery expects at least one request
with pytest.raises(KeyError):
prob.solve(cspy=False, pricing_strategy="Exact")
Expand Down Expand Up @@ -88,9 +85,10 @@ def test_mixed_fleet_consistency():
prob.solve()
G.edges["Source", "Sink"]["cost"] = [1, 2]
with pytest.raises(ValueError):
prob = VehicleRoutingProblem(
G, mixed_fleet=True, load_capacity=[2, 4], fixed_cost=[4]
)
prob = VehicleRoutingProblem(G,
mixed_fleet=True,
load_capacity=[2, 4],
fixed_cost=[4])
prob.solve()


Expand Down
Loading

0 comments on commit ff325cb

Please sign in to comment.