-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
What version of OR-Tools and what language are you using?
Version: 9.1.9490
Language: Python
Which solver are you using (e.g. CP-SAT, Routing Solver, GLOP, BOP, Gurobi)
Routing Solver
What operating system (Linux, Windows, ...) and version?
Linux
What did you do?
Steps to reproduce the behavior:
- Download complete program from https://developers.google.com/optimization/routing/vrp#entire_program1. Add
raise RuntimeError()somewhere indistance_callback. Example:
# Create and register a transit callback.
def distance_callback(from_index, to_index):
"""Returns the distance between the two nodes."""
# Convert from routing variable Index to distance matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
raise RuntimeError() # <----------- Simulate exception in callback
return data['distance_matrix'][from_node][to_node]- Run program.
- Objective value will be 0. Similarly, evaluations to
routing.GetArcCostForVehiclewill return 0.
What did you expect to see
Early termination of the program with a Python stacktrace. Alternatively a C++ crash or even a segmentation fault. Or simply a warning printed from C++.
What did you see instead?
Solution is found and objective value is 0. Similarly, evaluations to routing.GetArcCostForVehicle returns 0.
Objective: 0
Route for vehicle 0:
0 -> 0
Distance of the route: 0m
Route for vehicle 1:
0 -> 0
Distance of the route: 0m
Route for vehicle 2:
0 -> 0
Distance of the route: 0m
Route for vehicle 3:
0 -> 16 -> 15 -> 14 -> 13 -> 12 -> 11 -> 10 -> 9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0
Distance of the route: 0m
Maximum of the route distances: 0m
Note
This potential bug was discovered in a much more subtle setting:
A dummy node had been added and instead of updating the distance matrix with values, the transit cost was simply handled in the callback as follows:
def distance_callback(from_index, to_index):
"""Returns the distance between the two nodes."""
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
if from_node == dummy_depot_node:
return 0
# Naively assumed it would never try to drive back to the dummy_depot_node
# as the end node was specified to something else.
return dist_matrix[from_node][to_node]It worked fine when from_node was the dummy node, but when to_node was the dummy node, it would yield an IndexError on dist_matrix that would be silently ignored.
My solution was of course to do something like
if to_node == dummy_depot_node:
return 2**30But I believe there is still some unintended behavior here.