Skip to content

Commit 3effc38

Browse files
authored
Add files via upload
1 parent fb8f778 commit 3effc38

File tree

6 files changed

+488
-9
lines changed

6 files changed

+488
-9
lines changed

README.md

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
# vrptw-solver-comparison
2-
Solving Vehicle Rounting Problem with Time Windows using multiple Classic Heuristic, Metaheuristic algorithms (Hybrid Genetic Search (HGS), Guided Local Search (GLS), Ant Colony Optimisation (ACO), Simulated Annealing (SA)), then comparing the results with each one's results and represent it in the graph. This was my master's thesis project.
3-
4-
# keywords
5-
Vehicle Routing Problems with Time Window (VRPTW), Hybrid Genetic Search (HGS), Guided Local Search (GLS), Ant Colony Optimization (ACO), Simulated Annealing (SA), MACS-VRPTW, Genetic Algorithm (GA), Exact, Heuristics, Metaheuristics, Machine Learning Algorithms, GRASP, Local Search (LS), Neighborhood Search, OR-Tools, VRP, VRPTW, Vehicle Routing Problems (VRP), pyVRP.
6-
7-
# Note
8-
Using the Python Jupyter Notebook is highly advised. While compiling, each model executes independently. However, if you run the code straight from main.py , the application may crash and display errors due to the ACO procedure’s use of multiple threads! However, it functions perfectly now that I’m using the Python Jupyter Notebook code.
9-
101
# Development
112

123
## Create venv
@@ -25,3 +16,4 @@ python -m venv .venv
2516

2617
```sh
2718
pip install -r requirements.txt
19+
```

bks.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from vrplib import read_solution
2+
3+
def bks_solution(bks_path):
4+
BKS = read_solution(bks_path)
5+
BKS_ROUTES = BKS["routes"]
6+
BKS_COST = BKS["cost"]
7+
print("BKS cost:", BKS_COST)
8+
print("BKS solution:")
9+
for i, route in enumerate(BKS_ROUTES, start=1):
10+
print(f"Route #{i}: {' '.join(str(node) for node in route)}")
11+
print()
12+
13+
return BKS_ROUTES, BKS_COST

main.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import time
2+
from matplotlib import pyplot as plt
3+
from tabulate import tabulate
4+
from aco.solve import solve_with_aco
5+
from bks import bks_solution
6+
from hgs.solve import solve_with_hgs
7+
from gls.solve import solve_with_gls
8+
from plot import plot_my_solution
9+
from sa.solve import solve_using_sa
10+
from pyvrp import read
11+
12+
dataset = "r211"
13+
INPUT_PATH = f"data/{dataset}.txt"
14+
BKS_PATH = f"data/{dataset}.sol"
15+
RUNTIME = 120 # seconds
16+
17+
INSTANCE = read(INPUT_PATH, instance_format="solomon", round_func="trunc1")
18+
19+
result = {
20+
"bks": {},
21+
"hgs": {},
22+
"gls": {},
23+
"aco": {},
24+
"sa": {},
25+
}
26+
print("Running Algorithms on dataset:", dataset)
27+
result["bks"]["routes"], result["bks"]["cost"] = bks_solution(BKS_PATH)
28+
29+
start = time.time()
30+
result["hgs"]["routes"], result["hgs"]["cost"] = solve_with_hgs(INPUT_PATH, RUNTIME)
31+
result["hgs"]["runtime"] = time.time() - start
32+
33+
start = time.time()
34+
result["gls"]["routes"], result["gls"]["cost"] = solve_with_gls(INPUT_PATH, RUNTIME)
35+
result["gls"]["runtime"] = time.time() - start
36+
37+
start = time.time()
38+
result["aco"]["routes"], result["aco"]["cost"] = solve_with_aco(INPUT_PATH)
39+
result["aco"]["runtime"] = time.time() - start
40+
41+
start = time.time()
42+
result["sa"]["routes"], result["sa"]["cost"] = solve_using_sa(INPUT_PATH)
43+
result["sa"]["runtime"] = time.time() - start
44+
45+
_, ax = plt.subplots(figsize=(10, 10))
46+
plot_my_solution(result["hgs"], INSTANCE, ax=ax, dataset=dataset, algo="HGS")
47+
48+
_, ax = plt.subplots(figsize=(10, 10))
49+
plot_my_solution(result["gls"], INSTANCE, ax=ax, dataset=dataset, algo="GLS")
50+
51+
_, ax = plt.subplots(figsize=(10, 10))
52+
plot_my_solution(result["aco"], INSTANCE, ax=ax, dataset=dataset, algo="ACO")
53+
54+
_, ax = plt.subplots(figsize=(10, 10))
55+
plot_my_solution(result["sa"], INSTANCE, ax=ax, dataset=dataset, algo="SA")
56+
57+
gap = lambda bks_cost, algo_cost: round(100 * (algo_cost - bks_cost) / bks_cost, 2)
58+
header = ["Algorithms", "No. of Routes", "Costs", "Gap(%)", "Runtime(seconds)"]
59+
rows = [
60+
["BKS", len(result["bks"]["routes"]), result["bks"]["cost"], "-", "-"],
61+
[
62+
"HGS",
63+
len(result["hgs"]["routes"]),
64+
result["hgs"]["cost"],
65+
gap(result["bks"]["cost"], result["hgs"]["cost"]),
66+
result["hgs"]["runtime"],
67+
],
68+
[
69+
"GLS",
70+
len(result["gls"]["routes"]),
71+
result["gls"]["cost"],
72+
gap(result["bks"]["cost"], result["gls"]["cost"]),
73+
result["gls"]["runtime"],
74+
],
75+
[
76+
"ACO",
77+
len(result["aco"]["routes"]),
78+
result["aco"]["cost"],
79+
gap(result["bks"]["cost"], result["aco"]["cost"]),
80+
result["aco"]["runtime"],
81+
],
82+
[
83+
"SA",
84+
len(result["sa"]["routes"]),
85+
result["sa"]["cost"],
86+
gap(result["bks"]["cost"], result["sa"]["cost"]),
87+
result["sa"]["runtime"],
88+
],
89+
]
90+
print("Algorithm results on dataset:", dataset)
91+
tabulate(rows, header, tablefmt="html")

plot.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from typing import Optional
2+
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
6+
from pyvrp import ProblemData
7+
8+
9+
def plot_my_solution(
10+
solution: any,
11+
data: ProblemData,
12+
ax: Optional[plt.Axes] = None,
13+
dataset: str = "c101",
14+
algo: str = "HGS",
15+
):
16+
"""
17+
Plots the given solution.
18+
19+
Parameters
20+
----------
21+
solution
22+
Solution to plot.
23+
data
24+
Data instance underlying the solution.
25+
plot_clients
26+
Whether to plot clients as dots. Default False, which plots only the
27+
solution's routes.
28+
ax
29+
Axes object to draw the plot on. One will be created if not provided.
30+
"""
31+
if not ax:
32+
_, ax = plt.subplots()
33+
34+
dim = data.num_clients + 1
35+
x_coords = np.array([data.client(client).x for client in range(dim)])
36+
y_coords = np.array([data.client(client).y for client in range(dim)])
37+
38+
# This is the depot
39+
kwargs = dict(c="tab:red", marker="*", zorder=3, s=500)
40+
ax.scatter(x_coords[0], y_coords[0], label="Depot", **kwargs)
41+
42+
for idx, route in enumerate(solution["routes"], 1):
43+
x = x_coords[route]
44+
y = y_coords[route]
45+
46+
# Coordinates of clients served by this route.
47+
ax.scatter(x, y, label=f"Route {idx}", zorder=3, s=75)
48+
ax.plot(x, y)
49+
50+
# Edges from and to the depot, very thinly dashed.
51+
kwargs = dict(ls=(0, (5, 15)), linewidth=0.25, color="grey")
52+
ax.plot([x_coords[0], x[0]], [y_coords[0], y[0]], **kwargs)
53+
ax.plot([x[-1], x_coords[0]], [y[-1], y_coords[0]], **kwargs)
54+
55+
ax.grid(color="grey", linestyle="solid", linewidth=0.2)
56+
57+
ax.set_title(f"Solution - {dataset} - {algo} - {solution['cost']:.1f}")
58+
ax.set_aspect("equal", "datalim")
59+
ax.legend(frameon=False, ncol=2)

requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ortools==9.8.3296
2+
pandas==2.1.3
3+
pydantic==2.5.1
4+
pyvrp==0.6.3
5+
tabulate==0.9.0

solver.ipynb

Lines changed: 319 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)