Spaces:
Paused
Paused
| import numpy as np | |
| from scipy.spatial import distance | |
| from models.solvers.ortools.ortools_base import ORToolsBase | |
| class ORToolsCVRP(ORToolsBase): | |
| def __init__(self, large_value=1e+6, scaling=False): | |
| super().__init__(large_value, scaling) | |
| # @override | |
| def preprocess_data(self, node_feats): | |
| if self.scaling: | |
| node_feats = self.scaling_feats(node_feats) | |
| coords = node_feats["coords"] | |
| demands = node_feats["demand"] | |
| capacity = node_feats["capacity"] | |
| data = {} | |
| # convert set of corrdinates to a distance matrix | |
| dist_matrix = distance.cdist(coords, coords, "euclidean").round().astype(np.int64) | |
| data["distance_matrix"] = dist_matrix.tolist() | |
| data["num_vehicles"] = 10 | |
| data["depot"] = 0 | |
| data["demands"] = demands.tolist() | |
| data["vehicle_capacities"] = capacity.tolist() * data["num_vehicles"] | |
| return node_feats, data | |
| # @override | |
| def scaling_feats(self, node_feats): | |
| return { | |
| key: (node_feat * self.large_value).astype(np.int64) | |
| if key == "coords" else | |
| node_feat | |
| for key, node_feat in node_feats.items() | |
| } | |
| # @override | |
| def add_constraints(self, routing, transit_callback_index, manager, data, node_feats): | |
| def demand_callback(from_index): | |
| """Returns the demand of the node.""" | |
| # Convert from routing variable Index to demands NodeIndex. | |
| from_node = manager.IndexToNode(from_index) | |
| return data["demands"][from_node] | |
| demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback) | |
| routing.AddDimensionWithVehicleCapacity( | |
| demand_callback_index, | |
| 0, # null capacity slack | |
| data["vehicle_capacities"], # vehicle maximum capacities | |
| True, # start cumul to zero | |
| "Capacity" | |
| ) |