import os import numpy as np from utils.data_utils.dataset_base import DatasetBase from models.solvers.general_solver import GeneralSolver from models.classifiers.ground_truth.ground_truth_cvrptw import GroundTruthCVRPTW class CVRPTWDataset(DatasetBase): """ CVPRTW dataset by J.K. Falkner et al. https://arxiv.org/abs/2006.09100 L. Xin et al. also adopt the dataset (normalized coords ver.). https://arxiv.org/abs/2110.07983 """ def __init__(self, coord_dim, num_samples, num_nodes, solver="ortools", classifier="ortools", annotation=True, parallel=True, random_seed=1234, num_cpus=os.cpu_count()): super().__init__(coord_dim, num_samples, num_nodes, annotation, parallel, random_seed, num_cpus) # CAPACITY = { # 20: 500, # 50: 750, # 100: 1000 # } CAPACITY = { 10: 20, 20: 30, 50: 40, 100: 50 } self.capacity = CAPACITY[num_nodes] problem = "cvrptw" solver_type = solver classifier_type = classifier self.cvrptw_solver = GeneralSolver(problem=problem, solver_type=solver_type) self.classifier = GroundTruthCVRPTW(solver_type=classifier_type) # @override def generate_instance(self, seed): np.random.seed(seed) #------------- # coordinates #------------- coords = np.random.uniform(size=(self.num_nodes+1, self.coord_dim)) #--------- # demands #--------- # demands = np.random.normal(15, 10, (self.num_nodes+1, )).astype("int") # demands = np.maximum(np.minimum(np.ceil(np.abs(demands)), 42), 1) # clipping demands = np.random.randint(1, 10, size=(self.num_nodes+1, )) demands[0] = 0 #------------- # time window #------------- dist = np.sqrt(((coords[0:1] - coords) ** 2).sum(-1)) * 100 # define sampling horizon a0 = 0; b0 = 1000 a_sample = np.floor(dist) + 1 b_sample = b0 - a_sample - 10 # sample horizon of each node a = np.random.uniform(size=(self.num_nodes+1,)) a = (a * (b_sample - a_sample) + a_sample).astype("int") eps = np.maximum(np.abs(np.random.normal(0, 1, (self.num_nodes+1,))), 0.01) b = np.minimum(np.ceil(a + 300 * eps), b_sample) a[0] = a0; b[0] = b0 a = a / 100 b = b / 100 time_window = np.concatenate((a[:, None], b[:, None]), -1) return { "coords": coords, "demand": demands.astype(np.int64), "time_window": time_window, "grid_size": np.array([1.0]), "capacity": np.array([self.capacity], dtype=np.int64) } # @override def annotate(self, instance): # Solve CVRPTW node_feats = instance cvrptw_tours = self.cvrptw_solver.solve(node_feats) if cvrptw_tours is None: return inputs = self.classifier.get_inputs(cvrptw_tours, 0, node_feats) labels = self.classifier(inputs, annotation=True) instance.update({"tour": cvrptw_tours, "labels": labels}) return instance