Exemplo n.º 1
0
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()
Exemplo n.º 2
0
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