class Construction: def __init__(self): self.AM = Model().solve() # return the values of the model, list self.one = ReadData("TTRP_01.txt") self.truck_num = 5 self.trailer_num = 3 # different TTRP_xx.txt need different argument # self.all_locations = [['a', ['30.0', '40.0']]] + self.one.get_locations() # 01.txt self.all_locations = [['a', ['30.0', '40.0']] ] + self.one.get_locations() # 02.txt # compute the distance of two nodes def compute_dist(self, i, j): for node in self.all_locations: if i == node[0]: cord_i = node[1] if j == node[0]: cord_j = node[1] dist_ij = hypot( float(cord_i[0]) - float(cord_j[0]), float(cord_i[1]) - float(cord_j[1])) return dist_ij # get the five tours def get_tours(self): seqs = [] for i in range(self.truck_num): seq = range(i, self.one.customer_num * self.truck_num, self.truck_num) seqs.append(seq) tours = [] for seq in seqs: tour = [] for index in seq: if self.AM[index] > 0.5: tour.append((ceil((index + 1) / self.truck_num)) - 1) # for a standard index tour.append('a') # add the index of depot, awful code tours.append(tour) return tours # find the closest neighbor to a given node in the tour def closest_neighbor(self, current_tour, node): dists = {} for cus in current_tour: if cus == node: continue dist = self.compute_dist(node, cus) dists.update({cus: dist}) return sorted(dists.items(), key=itemgetter(1))[0][0] # add node k between node i and node j def add(self, i, j, k): return self.compute_dist(i, k) + self.compute_dist( k, j) - self.compute_dist(i, j) def add_closest_to_tour(self, current_tour, tour): best_cost, new_tour = float('inf'), None for k in current_tour: if k in tour: continue for index in range(len(tour) - 1): cost = self.add(tour[index], tour[index + 1], k) if cost < best_cost: best_cost = cost new_tour = tour[:index + 1] + [k] + tour[index + 1:] return new_tour def cheapest_insertion(self, current_tour): # print("cheapest current tour", current_tour) # print(len(current_tour)) # f**k = len(current_tour) # current_tour = self.get_tours()[0] # for tour in self.get_tours(): # only 2 point, do nothing if len(current_tour) == 2: return current_tour # a route only one point, it means: # tr\pv\main_tours only have 'a'; sub-tours only have root elif len(current_tour) == 1: return [] starter = random.choice(current_tour) # print(starter) tour, tours = [starter], [] neighbor = self.closest_neighbor(current_tour, starter) tour.append(neighbor) # the first [i, j] list # print(tour) while len(tour) != len(current_tour): tour = self.add_closest_to_tour(current_tour, tour) tours.append(tour) # print(tour) return tour def check_route(self, tour): # type_list = [] # for tour in self.get_tours(): types = [] for cus in tour: if cus == 'a': types.append(2) else: types.append(self.one.get_types()[cus]) # type_list.append(types) return types def tour_length(self, tour): tour_length = 0.0 if len(tour) == 0: return tour_length elif len(tour) == 1: return tour_length elif len(tour) == 2: return self.compute_dist(tour[0], tour[1]) else: for i in range(len(tour) - 1): tour_length += self.compute_dist(tour[i], tour[i + 1]) tour_length += self.compute_dist(tour[0], tour[-1]) # because it's a circle return tour_length def pure_truck(self): pure_truck = [] for route in self.get_tours()[self.trailer_num:]: tour = self.cheapest_insertion(route) # pure_truck.append([tour, self.tour_length(tour)]) pure_truck.append(tour) return pure_truck def pure_vehicle(self): pure_vehicle = [] for tour in self.get_tours()[:self.trailer_num]: if 1 not in self.check_route(tour): pure_vehicle.append(tour) return pure_vehicle def main_sub(self): mains_subs = [] for tour in self.get_tours()[:self.trailer_num]: if 1 in self.check_route(tour): init_main, init_sub = [], [] for cus in tour: if cus == 'a': init_main.append(cus) elif self.one.get_types()[cus] == 0: init_main.append(cus) else: init_sub.append(cus) mains_subs.append([init_main, init_sub]) return mains_subs def sub_num(self, s): sub_demands = 0.0 for cus in s: sub_demands += self.one.get_demands()[ cus] # s 中的索引和 get_demands 中的一样吗❓ return ceil(sub_demands / self.one.truck_cap) # def complete_tour(self, ms): def complete_tour(self, ms): main_tour = self.cheapest_insertion(ms[0]) # 储存所有的子路径 # 如果只有一个子路径,查询为 subs[0] subs = [] temp_s = ms[1] for i in range(self.sub_num(ms[1])): sub_demands = 0.0 s = [] for cus in temp_s: sub_demands += self.one.get_demands()[cus] if sub_demands < self.one.truck_cap: s.append(cus) subs.append(s) # 这里是移除上面循环中符合条件的客户 temp_s = [x for x in temp_s if x not in s] sub_tour = [] for sub in subs: # 连接点不能是仓库,所以是 [:-1] connector = self.closest_neighbor(ms[0][:-1], sub[0]) sub.append(connector) sub_tour.append(self.cheapest_insertion(sub)) # complete_tours = [main_tour, sub_tour, self.tour_length(main_tour) + self.tour_length(sub_tour)] complete_tours = [main_tour, sub_tour] return complete_tours def all_complete_tour(self): complete_tours = [] for ms in self.main_sub(): complete_tours.append(self.complete_tour(ms)) return complete_tours def total_length(self): length = 0.0 for route in self.pure_truck(): length += self.tour_length(route) for route in self.pure_vehicle(): length += self.tour_length(route) cv = self.all_complete_tour() main_tours, sub_tours = [], [] for seqs in cv: main_tours.append(seqs[0]) sub_tours.append(seqs[1]) # this will be a list of list of list split_sub_tours = [] for tour in sub_tours: split_sub_tours += tour for route in main_tours: length += self.tour_length(route) for route in split_sub_tours: length += self.tour_length(route) return length def all_route(self): return self.pure_truck(), self.pure_vehicle(), self.all_complete_tour()
class Assignment: def __init__(self): self.one = ReadData("TTRP_01.txt") self.truck_num = 5 self.trailer_num = 3 def costs_all(self): dists_di = [] # n = 0 for i in self.one.get_locations(): # (1)仓库到客户 i 的距离,存储为索引和距离的列表 dist_di = hypot( float(self.one.depot_loc[0]) - float(i[1][0]), float(self.one.depot_loc[1]) - float(i[1][1])) dists_di.append([i[0], float(dist_di)]) # n += 1 # 保证索引从 0 开始 # print(dists_di) # return dists_di # def seed_sets(self): # 按照与仓库的距离选 first 种子点,选10次,拿到索引 rank_dist = sorted(dists_di, key=lambda dist_di: dist_di[1]) seeds1_ind = [] dist_ds = [] # (2)存储仓库到种子点的距离值 for i in range(10): seeds1_ind.append(rank_dist[i][0]) dist_ds.append(rank_dist[i][1]) # print(seeds1_ind) # print(dist_ds) # 选种子点集合,这部分可能在计算上有错误... # 选择种子点,组成 seed set,根据 1st 种子点的不同,有不同的 seed set seed_sets = [] cus_sets = [] for seed1 in seeds1_ind: seed_set = [seed1] # seed_set = [45, 10] # print("初始种子点:", seed_set) dists = [] cus = self.one.get_locations() for i in seed_set: for j in cus: if j[0] == i: cus.remove(j) # print("初始的 cus 长度:", len(cus)) while len(seed_set) < self.truck_num: dists_sum = [] for i in cus: dist_ipsum = 0.0 # ind_i = one.get_locations().index(i) dist_i = dists_di[i[0]][1] # print(dist_i) for pseed in seed_set: dist_ip = hypot( float(i[1][0]) - float(self.one.get_locations()[pseed][1][0]), float(i[1][1]) - float(self.one.get_locations()[pseed][1][1])) dist_ipsum += dist_ip # print(dist_ip) # print("ipsum:", dist_ipsum) dist_isum = dist_i + dist_ipsum dists_sum.append([i[0], dist_isum]) # print(len(dists_sum)) rank_sum = sorted(dists_sum, key=lambda dist_sum: dist_sum[1]) # print(rank_sum) seed_set.append(rank_sum[0][0]) for i in cus: if i[0] == rank_sum[0][0]: cus.remove(i) # print("这里是cus:", len(cus)) # print(seed_set) seed_sets.append(seed_set) # print("last cus", len(cus)) cus_sets.append(cus) # print(len(cus_sets)) # 10组 # print(cus_sets) # 10组 每组是除了种子点的其余点 # print(seed_sets) # 10组 每组5个值(跟卡车数或者说路线数相同) # return seed_sets # def costs_all(self): # 求解指派花费 d_ij 这里的 j 是卡车数,也其实是路径数 # cost_ij = dists_id + dist_is + dist_sd costs_ij = [] # i 到种子点(五个索引的集合) costs_all = [] for t in range(10): costs = [] # for i in cus_sets[t]: # dist_id = hypot(float(i[1][0]) - float(one.depot_loc[0]), # float(i[1][1]) - float(one.depot_loc[1])) for i in dists_di: dist_id = i[1] cost = [] for seed in seed_sets[t]: # dist_is = hypot(float(i[1][0]) - float(one.get_locations()[seed][1][0]), # float(i[1][1]) - float(one.get_locations()[seed][1][1])) # 客户到各个路线的种子点的距离 dist_is = hypot( float(self.one.get_locations()[i[0]][1][0]) - float(self.one.get_locations()[seed][1][0]), float(self.one.get_locations()[i[0]][1][1]) - float(self.one.get_locations()[seed][1][1])) dist_sd = hypot( float(self.one.get_locations()[seed][1][0]) - float(self.one.depot_loc[0]), float(self.one.get_locations()[seed][1][1]) - float(self.one.depot_loc[1])) cost_ij = dist_id + dist_is + dist_sd # 这里对每个路线下的客户 i 计算了一次 d_ij cost.append(cost_ij) # print(cost) # print() costs.extend(cost) costs_all.append(costs) # print("应该是十组之一", len(costs)) # 长度为(剔除了路线点)客户数 # print(len(costs_all)) # 10组 # 哪一组是最好的呢? return costs_all