Python Forum
Need Help with Vehicle Routing Problem with Time Windows (VRPTW) in Python
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Need Help with Vehicle Routing Problem with Time Windows (VRPTW) in Python
#1
Question 
Hello,
I've been working on developing a solution for a Vehicle Routing Problem with Time Windows (VRPTW). I found a code example on GitHub which I adapted to work in Python. However, we're encountering issues when we try to run the code with our own distance matrix, tested with a 10x10 matrix – it's not working.

We're using Gurobi for optimization, which should theoretically be able to solve the problem. Additionally, we think there might be some constraints in our model that potentially render the problem infeasible, but we're struggling to pinpoint the exact issue.

Here's a brief overview of our task:

- We have 90 locations, but are currently testing with 10 to simplify.

- Arrival at the first stop (a central depot) is at 10:00 (600 minutes) - this is an estimate.

- Return to the second stop (end location) must be by 12:30 - also an estimate.

- Our matrix indicates time in minutes between locations. Currently, the route can be completed with 9 vehicles, but we aim to reduce this to 8 or fewer.

- Each point must be visited exactly once (departures from location 1 = number of vehicles, arrivals at location 2 = number of vehicles) as all routes must start at location 1 and end at location 2.

- All other locations must be visited exactly once with precisely one departure (arrival at a location followed by departure).

- Departure from each stop is 5 minutes after arrival (service time)

It's worth noting that the code we're basing this on has a capacity constraint, which we don't have in our problem. We've based our work on the following code from GitHub:
https://github.com/ruthmair/vrp/blob/main/vrptw.ipynb
Hoping for some advice, guidelines, or assistance with the code. We're a bit out of our depth here, but any help would be greatly appreciated if you can spare the time. 😊

Here are our current code:
import gurobipy as gp
from gurobipy import GRB

# INSTANCE CONFIGURATION
numCustomers = 9  # 9 customers plus the depot
maxNumVehicles = 6  # Increased number of vehicles
vehicleCapacity = 40  # Increased vehicle capacity
timeHorizon = 900  # Extended time horizon to 3:00 pm (900 minutes)

# Time matrix (depot + 9 customers)
time_matrix = [
    [0.00, 17.00, 60.80, 38.08, 23.88, 31.58, 50.05, 50.17, 50.17, 28.20],
    [16.82, 0.00, 55.80, 35.98, 21.78, 30.42, 48.83, 48.05, 48.05, 29.15],
    [60.65, 55.40, 0.00, 42.52, 47.17, 36.97, 19.80, 19.78, 19.78, 36.50],
    [36.30, 36.67, 43.40, 0.00, 19.92, 9.67, 27.57, 27.68, 27.68, 9.27],
    [21.35, 21.73, 46.75, 18.95, 0.00, 13.40, 32.10, 31.03, 31.03, 11.83],
    [30.13, 31.22, 37.95, 9.35, 14.47, 0.00, 22.12, 22.23, 22.23, 4.08],
    [48.47, 48.83, 19.80, 27.45, 32.10, 21.88, 0.00, 0.97, 0.97, 21.43],
    [48.73, 49.10, 19.75, 27.72, 32.35, 22.15, 1.08, 0.00, 0.00, 23.08],
    [48.73, 49.10, 19.75, 27.72, 32.35, 22.15, 1.08, 0.00, 0.00, 23.08],
    [28.20, 28.58, 38.80, 11.00, 11.83, 4.08, 22.97, 23.08, 23.08, 0.00]
]

# Convert the time matrix to a dictionary format suitable for Gurobi
travelTimes = {(i, j): time_matrix[i][j] for i in range(numCustomers + 1) for j in range(numCustomers + 1)}

# Reduced Service time to 2 minutes at each stop
serviceTimes = {i: 2 for i in range(numCustomers + 1)}

# More flexible uniform time window for all customers
timeWindows = {i: (600, timeHorizon) for i in range(numCustomers + 1)}

# Create model
model = gp.Model("VRPTW")

locations = [i for i in range(numCustomers + 1)]
connections = [(i, j) for i in locations for j in locations if i != j]

# Decision variable for routing
x = model.addVars(connections, vtype=GRB.BINARY, name="x")
model.setObjective(gp.quicksum(travelTimes[i, j] * x[i, j] for i, j in connections), GRB.MINIMIZE)

# Constraints
model.addConstrs((x.sum("*", j) == 1 for j in locations if j != 0), name="incoming")
model.addConstrs((x.sum(i, "*") == 1 for i in locations if i != 0), name="outgoing")
model.addConstr(x.sum(0, "*") <= maxNumVehicles, name="maxNumVehicles")

# Time Constraints - Adjusted for more flexibility
y = model.addVars(locations, name="y")
for i in locations:
    y[i].LB = timeWindows[i][0]
    y[i].UB = timeWindows[i][1]

model.addConstrs((y[i] + serviceTimes[i] + travelTimes[i, j] <= y[j] + (timeHorizon - y[j]) * (1 - x[i, j])
                  for i, j in connections if i != j), name="timeBigM")

# Solve the model
model.params.Threads = 4
model.optimize()

# Check for infeasibility
if model.status == GRB.INFEASIBLE:
    print('Model is infeasible')
    model.computeIIS()
    model.write("model.ilp")
else:
    # Solution Retrieval
    usedConnections = [(i, j) for (i, j) in x.keys() if x[i, j].X > 0.5]
    nextCustomer = {}
    for (i, j) in usedConnections:
        if i == 0:
            if 0 not in nextCustomer:
                nextCustomer[0] = []
            nextCustomer[0].append(j)
        else:
            nextCustomer[i] = j

    print(f"Solution contains {len(nextCustomer[0])} routes:")
    routeNumber = 0
    visitedCustomers = [False] * (numCustomers + 1)
    for firstCustomer in nextCustomer[0]:
        print(f"Route {routeNumber}: 0 -> ", end="")
        vehicleLoad = 0
        time = travelTimes[0, firstCustomer]
        violatedTimeWindows = False
        currentCustomer = firstCustomer
        while currentCustomer != 0:
            print(f"{currentCustomer} (L:{vehicleLoad}, T:{time}) -> ", end="")
            visitedCustomers[currentCustomer] = True
            vehicleLoad += 1  # Assuming each customer has a demand of 1 unit
            time = max(time, timeWindows[currentCustomer][0])
            if time > timeWindows[currentCustomer][1]:
                violatedTimeWindows = True
            time += (serviceTimes[currentCustomer] + travelTimes[currentCustomer, nextCustomer[currentCustomer]])
            currentCustomer = nextCustomer[currentCustomer]
        print(f"0 (L:{vehicleLoad}/{vehicleCapacity}, T:{time})")
        if vehicleLoad > vehicleCapacity:
            print("Vehicle capacity is exceeded!")
        if violatedTimeWindows:
            print("Time windows are violated!")
        routeNumber += 1

    print("Unvisited customers: ", end="")
    for c in range(1, numCustomers + 1):
        if not visitedCustomers[c]:
            print(f"{c}, ", end="")

    # Free resources
    model.dispose()
    gp.disposeDefaultEnv()
snippsat write Nov-10-2023, 02:18 PM:
Added code tag in your post,look at BBCode on how to use.
Reply
#2
(Nov-10-2023, 10:33 AM)kasper321421312 Wrote: I've been working on developing a solution for a Vehicle Routing Problem with Time Windows (VRPTW). I found a code example on GitHub which I adapted to work in Python. However, we're encountering issues when we try to run the code with our own distance matrix, tested with a 10x10 matrix – it's not working.
Try to start with smaller matrix,if i try to run it now will take a very long time i stopped long before fishes.
Test with a smaller set of locations to ensure the basic logic is sound,then scale up.
Eg somting like this.
# INSTANCE CONFIGURATION
numCustomers = 2  # 2 customers plus the depot
maxNumVehicles = 2  # Adjusted number of vehicles
vehicleCapacity = 40  # As per your setup
timeHorizon = 900  # As per your setup

# Time matrix (depot + 2 customers)
time_matrix = [
    [0.00, 17.00, 23.88],
    [16.82, 0.00, 21.78],
    [21.35, 21.73, 0.00]
]
# INSTANCE CONFIGURATION
numCustomers = 7  # 7 customers plus the depot
maxNumVehicles = 3  # Adjusted number of vehicles
vehicleCapacity = 40  # As per your setup
timeHorizon = 900  # As per your setup

# Time matrix (depot + 7 customers)
time_matrix = [
    [0.00, 17.00, 23.88, 31.58, 28.20, 35.00, 40.00, 45.00],
    [16.82, 0.00, 21.78, 30.42, 29.15, 33.00, 38.00, 43.00],
    [21.35, 21.73, 0.00, 13.40, 11.83, 20.00, 25.00, 30.00],
    [30.13, 31.22, 14.47, 0.00, 4.08, 12.00, 17.00, 22.00],
    [28.20, 28.58, 11.83, 4.08, 0.00, 10.00, 15.00, 20.00],
    [35.00, 33.00, 20.00, 12.00, 10.00, 0.00, 5.00, 10.00],
    [40.00, 38.00, 25.00, 17.00, 15.00, 5.00, 0.00, 5.00],
    [45.00, 43.00, 30.00, 22.00, 20.00, 10.00, 5.00, 0.00]
]
The last one will take ca 25-sec.
Now it easier to see if this smaller solves it correctly.
Look to see if Gurobi's has debugging tools to pinpoint which constraints are causing issues.
How do I debug a Gurobi model?
Also code start to get long with no structure like eg functions,
if code are corrct at one point could return that result out,then the problem code will be in one place.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Multiple.ui windows showing at the same time when I only want to show at a time eyavuz21 4 1,038 Dec-20-2022, 05:14 AM
Last Post: deanhystad
  Problem with module time and leap seconds Pedroski55 3 1,259 Oct-07-2022, 11:27 PM
Last Post: Pedroski55
  How to change UTC time to local time in Python DataFrame? SamKnight 2 1,616 Jul-28-2022, 08:23 AM
Last Post: Pedroski55
  Programming a routing protocol leemao 2 2,191 Jul-13-2021, 05:47 PM
Last Post: leemao
  What are the available softwares used to edit and simulate network routing protocols? leemao 1 1,923 Dec-25-2019, 05:36 PM
Last Post: Larz60+
  Kivy pip installation problem (windows 10) sebastian 1 4,326 Dec-10-2019, 04:00 PM
Last Post: snippsat
  time.sleep(...) problem DPaul 3 2,814 Jan-28-2019, 11:40 AM
Last Post: Larz60+
  'Time Limit Exceeded' Problem bkpee3 2 5,444 Nov-14-2018, 03:51 AM
Last Post: bkpee3
  Multi-processing - problem with running multiple *.py files at the same time Antonio 5 3,822 Sep-12-2018, 01:08 PM
Last Post: volcano63
  Anaconda on Windows 10: problem with Jupyter Notebook lupoalberto 8 13,110 Apr-18-2018, 08:08 AM
Last Post: lupoalberto

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020