class UniqueItemsCounter:
def __init__(self, data, manager,vehicle):
self.data = data
self.manager = manager
self.vehicle = vehicle
self.visited_items = set()
def __call__(self, from_index):
vehicle_id = self.vehicle
from_node = self.manager.IndexToNode(from_index)
previous_item_type_count = 0
current_item_type_count = 0
if from_node == self.data['depot']:
self.visited_items = set() # Reset items when at depot
if from_node != self.data['depot']:
previous_item_type_count = len(self.visited_items)
self.visited_items.update(
self.data['item_type'][from_node])
current_item_type_count = len(self.visited_items)
return current_item_type_count-previous_item_type_count
unique_items_callback_indices = []
for vehicle_id in range(data['num_vehicles']):
unique_items_callback_indices.append(
routing.RegisterUnaryTransitCallback(
UniqueItemsCounter(data, manager, vehicle_id)))
routing.AddDimensionWithVehicleTransits(
unique_items_callback_indices,
0, # no slack
data['cluster_size'], # vehicle capacity
True, # start cumul to zero
'UniqueItems')
unique_items_dimension = routing.GetDimensionOrDie('UniqueItems')
unique_items_dimension.SetSpanCostCoefficientForAllVehicles(1)
# Add the constraint to return to depot when max unique items limit is reached
# for vehicle_id in range(data['num_vehicles']):
# unique_items_dimension.CumulVar(routing.End(vehicle_id)).SetMax(data['cluster_size'])
penalty = 1000
for node in range(1, len(data['travel_times'])):
routing.AddDisjunction([manager.NodeToIndex(node)], penalty)