Constraint makes or-tools routing problem impossible

60 Views Asked by At

Problem

I have n possible houses to visit, k walkers (vehicles), and m possible depot locations. The goal is to maximize the number of houses visited by precisely k walkers. A walker can choose any of the m possible depot locations at no cost (and the optimizer should thus choose the depot location which maximizes the number of total houses visited). Any number of walkers may start at the same depot location (at no penalty). A walker must start the route at its depot and return to it at the end.

Modeling

To model this problem, I'm just making m depots, and placing MAX_VEHICLES_PER_DEPOT (set to 3 for this example) vehicles at each depot (could be up to k, but this makes the problem complexity much larger). Then, I'd like to constrain the number of used vehicles to k. Imposing this constraint seems to make the problem impossible, although I don't know why.

Code

My example problem has 283 houses (self.num_houses) and 56 possible depots (self.num_depots), so it doesn't seem too large at all. The following code works perfectly, and new solutions are found about every 2 ms. This code doesn't impose the constraint that the number of active vehicles must be k (so I get many short routes).

data = {}
data["num_vehicles"] = self.MAX_VEHICLES_PER_DEPOT * self.num_depots
data["num_depots"] = self.num_depots
data["num_points"] = self.num_houses + self.num_depots
data["starts"] = [i for i in range(self.num_depots)] * self.MAX_VEHICLES_PER_DEPOT
data["ends"] = [i for i in range(self.num_depots)] * self.MAX_VEHICLES_PER_DEPOT

self.manager = pywrapcp.RoutingIndexManager(
    data["num_points"], data["num_vehicles"], data["starts"], data["ends"]
)

self.routing = pywrapcp.RoutingModel(self.manager)

self.distance_matrix = (self.distance_matrix / WALKING_M_PER_S).round().astype(int).tolist()
transit_callback_index = self.routing.RegisterTransitMatrix(self.distance_matrix)
self.routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# Add Time constraint.
time_dimension_name = "Time"
self.routing.AddDimension(
    transit_callback_index,
    90,  # time at each node
    3600,  # vehicle maximum travel distance
    True,  # start cumul to zero
    time_dimension_name,
)
distance_dimension = self.routing.GetDimensionOrDie(time_dimension_name)
distance_dimension.SetGlobalSpanCostCoefficient(100)

# ADD NUM VEHICLES CONSTRAINT HERE (described below)

# Allow dropping nodes
penalty = 10000
for node in range(1, self.num_houses + 1):
    self.routing.AddDisjunction([self.manager.NodeToIndex(node)], penalty)

search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.log_search = True
search_parameters.first_solution_strategy = (
    routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
)

search_parameters.time_limit.seconds = 30
solution = self.routing.SolveWithParameters(search_parameters)

The following constraint is meant to restrict the number of used vehicles to the prescribed number. However, when adding this code (where it says # ADD NUM VEHICLES CONSTRAINT HERE above), no solutions are found. Specifically, the log line "I0000 00:00:1702567665.531444 15337 search.cc:282] Root node processed (time = 1 ms, constraints = 3285, memory used = 275.61 MB)" is printed, and then nothing until the time limit is reached.

# Constrain the total number of used vehicles to be = num_lists
workers = [self.routing.ActiveVehicleVar(i) for i in range(data["num_vehicles"])]
self.routing.solver().Add(
    self.routing.solver().Sum(workers) == self.num_lists
)

My guess is this constraint somehow makes the problem impossible, since not even an initial solution is found (even running it for a few minutes). Any ideas why? I'm guessing I'm doing this constraining wrong. Thanks!

0

There are 0 best solutions below