def two_opt_double(route1: Route, route2: Route): arc_list1 = route1.required_arc_list arc_list2 = route2.required_arc_list idx1 = (len(arc_list1) - 1) // 2 idx2 = (len(arc_list2) - 1) // 2 half11 = arc_list1[:idx1] half12 = arc_list1[idx1:] half21 = arc_list2[:idx2] half22 = arc_list2[idx2:] load11 = 0 for arc in half11: load11 += arc[0][IDX_DEMAND] load12 = route1.load - load11 load21 = 0 for arc in half21: load21 += arc[0][IDX_DEMAND] load22 = route2.load - load21 l1 = load11 + load22 l2 = load12 + load21 l3 = load11 + load21 l4 = load12 + load22 new_route1 = new_route2 = new_route3 = new_route4 = None if l1 < CAPACITY and l2 < CAPACITY: new_route1 = Route() new_route1.required_arc_list = half11 + half22 new_route1.load = l1 new_route1.cost = get_route_cost(new_route1.required_arc_list) new_route2 = Route() new_route2.required_arc_list = half21 + half12 new_route2.load = l2 new_route2.cost = get_route_cost(new_route2.required_arc_list) if l3 < CAPACITY and l4 < CAPACITY: new_route3 = Route() reverse21 = deepcopy(half21) for arc in reverse21: arc[1] = not arc[1] reverse21.reverse() new_route3.required_arc_list = half11 + reverse21 new_route3.load = l3 new_route3.cost = get_route_cost(new_route3.required_arc_list) new_route4 = Route() reverse12 = deepcopy(half12) for arc in reverse12: arc[1] = not arc[1] reverse12.reverse() new_route4.required_arc_list = reverse12 + half22 new_route4.load = l4 new_route4.cost = get_route_cost(new_route4.required_arc_list) if new_route1 is None and new_route3 is None: return None, None elif new_route1 is None: return new_route3, new_route4 elif new_route3 is None: return new_route1, new_route2 else: if new_route1.cost + new_route2.cost < new_route3.cost + new_route4.cost: return new_route1, new_route2 else: return new_route3, new_route4
def two_opt_single(route: Route): arc_list = route.required_arc_list # extract sub-route indices idx = sample(range(len(arc_list)), 2) if idx[0] < idx[1]: start, end = idx else: end, start = idx # create a new route new_route = Route() new_sub_list = deepcopy(arc_list[start: end + 1]) for arc in new_sub_list: arc[1] = not arc[1] new_sub_list.reverse() new_arc_list = arc_list[: start] + new_sub_list + arc_list[end + 1:] new_route.required_arc_list = new_arc_list new_route.cost = get_route_cost(new_arc_list) new_route.load = route.load return new_route
def swap(solution): route_list = solution.route_list route_list_length = len(route_list) route_idx_1 = randrange(0, route_list_length) route_1 = route_list[route_idx_1] route_idx_2 = randrange(0, route_list_length - 1) if route_idx_2 >= route_idx_1: route_idx_2 += 1 route_2 = route_list[route_idx_2] arc_list_1 = route_1.required_arc_list arc_list_2 = route_2.required_arc_list arc_idx_1 = randrange(0, len(arc_list_1)) load_1 = route_1.load load_2 = route_2.load arc_1 = arc_list_1[arc_idx_1] demand_1 = arc_1[0][IDX_DEMAND] flag = False arc_2 = arc_idx_2 = new_load_1 = new_load_2 = None for arc_idx_2 in range(0, len(arc_list_2)): arc_2 = arc_list_2[arc_idx_2] demand_2 = arc_2[0][IDX_DEMAND] new_load_1 = load_1 + demand_2 - demand_1 new_load_2 = load_2 + demand_1 - demand_2 if new_load_1 <= CAPACITY and new_load_2 <= CAPACITY: flag = True break # swapping two routes is better than swapping one route if flag: new_arc_list_11 = arc_list_1[:] new_arc_list_12 = arc_list_1[:] new_arc_list_21 = arc_list_2[:] new_arc_list_22 = arc_list_2[:] new_arc_list_11[arc_idx_1] = arc_2 new_arc_list_12[arc_idx_1] = [arc_2[0], not arc_2[1]] new_arc_list_21[arc_idx_2] = arc_1 new_arc_list_22[arc_idx_2] = [arc_1[0], not arc_1[1]] cost11 = get_route_cost(new_arc_list_11) cost12 = get_route_cost(new_arc_list_12) cost21 = get_route_cost(new_arc_list_21) cost22 = get_route_cost(new_arc_list_22) new_route_1 = Route() new_route_2 = Route() new_route_1.load = new_load_1 new_route_2.load = new_load_2 if cost11 < cost12: new_route_1.required_arc_list = new_arc_list_11 new_route_1.cost = cost11 else: new_route_1.required_arc_list = new_arc_list_12 new_route_1.cost = cost12 if cost21 < cost22: new_route_2.required_arc_list = new_arc_list_21 new_route_2.cost = cost21 else: new_route_2.required_arc_list = new_arc_list_22 new_route_2.cost = cost22 new_route_list = route_list[:] new_route_list[route_idx_1] = new_route_1 new_route_list[route_idx_2] = new_route_2 new_solution = Solution() new_solution.route_list = new_route_list new_solution.quality = solution.quality + new_route_1.cost - route_1.cost + new_route_2.cost - route_2.cost return new_solution else: new_route = Route() new_route.load = route_1.load arc_list_1_length = len(arc_list_1) if arc_list_1_length < 2: return solution arc_idx_2 = randrange(0, arc_list_1_length - 1) if arc_idx_2 >= arc_idx_1: arc_idx_2 += 1 arc_2 = arc_list_1[arc_idx_2] new_arc_list_1 = arc_list_1[:] new_arc_list_2 = arc_list_1[:] new_arc_list_3 = arc_list_1[:] new_arc_list_4 = arc_list_1[:] new_arc_list_1[arc_idx_1] = arc_2 new_arc_list_1[arc_idx_2] = arc_1 new_arc_list_2[arc_idx_1] = [arc_2[0], not arc_2[1]] new_arc_list_2[arc_idx_2] = arc_1 new_arc_list_3[arc_idx_1] = arc_2 new_arc_list_3[arc_idx_2] = [arc_1[0], not arc_1[1]] new_arc_list_4[arc_idx_1] = [arc_2[0], not arc_2[1]] new_arc_list_4[arc_idx_2] = [arc_1[0], not arc_1[1]] cost1 = get_route_cost(new_arc_list_1) cost2 = get_route_cost(new_arc_list_2) cost3 = get_route_cost(new_arc_list_3) cost4 = get_route_cost(new_arc_list_4) min_cost = min(cost1, cost2, cost3, cost4) new_route.cost = min_cost if cost1 == min_cost: new_route.required_arc_list = new_arc_list_1 elif cost2 == min_cost: new_route.required_arc_list = new_arc_list_2 elif cost3 == min_cost: new_route.required_arc_list = new_arc_list_3 else: new_route.required_arc_list = new_arc_list_4 new_solution = Solution() new_route_list = route_list[:] new_route_list[route_idx_1] = new_route new_solution.route_list = new_route_list new_solution.quality = solution.quality + new_route.cost - route_1.cost return new_solution
def single_insertion(solution: Solution): route_list = solution.route_list remove_route_idx = randrange(0, len(route_list)) remove_route = route_list[remove_route_idx] remove_arc_list = remove_route.required_arc_list remove_arc_idx = randrange(0, len(remove_arc_list)) remove_arc = remove_arc_list[remove_arc_idx] demand = remove_arc[0][IDX_DEMAND] insert_route_idx = None for i in range(len(route_list)): if i != remove_route_idx and route_list[i].load + demand < CAPACITY: insert_route_idx = i break if insert_route_idx is not None: insert_route = route_list[insert_route_idx] insert_arc_list = insert_route.required_arc_list insert_arc_idx = randrange(0, len(insert_arc_list) + 1) insert_arc = remove_arc new_insert_route = Route() new_insert_arc_list_1 = insert_arc_list[:] new_insert_arc_list_2 = insert_arc_list[:] new_insert_arc_list_1.insert(insert_arc_idx, insert_arc) new_insert_arc_list_2.insert(insert_arc_idx, [insert_arc[0], not insert_arc[1]]) cost1 = get_route_cost(new_insert_arc_list_1) cost2 = get_route_cost(new_insert_arc_list_2) if cost1 < cost2: new_insert_route.required_arc_list = new_insert_arc_list_1 new_insert_route.cost = cost1 else: new_insert_route.required_arc_list = new_insert_arc_list_2 new_insert_route.cost = cost2 new_insert_route.load = insert_route.load + demand new_route_list = route_list[:] new_remove_arc_list = remove_arc_list[:] new_remove_route = None del new_remove_arc_list[remove_arc_idx] # update insert route first new_route_list[insert_route_idx] = new_insert_route if not new_remove_arc_list: del new_route_list[remove_route_idx] else: new_remove_route = Route() new_remove_route.required_arc_list = new_remove_arc_list new_remove_route.load = remove_route.load - demand new_remove_route.cost = get_route_cost(new_remove_arc_list) new_route_list[remove_route_idx] = new_remove_route diff1 = (0 if new_remove_route is None else new_remove_route.cost) - remove_route.cost diff2 = new_insert_route.cost - insert_route.cost # print('cost1', diff1 + diff2) new_solution = Solution() new_solution.route_list = new_route_list new_solution.quality = solution.quality + diff1 + diff2 # print(new_solution.quality, get_quality(new_route_list)) return new_solution else: length = len(remove_arc_list) if length < 2: return solution insert_arc_idx = randrange(0, length - 1) if insert_arc_idx >= remove_arc_idx: insert_arc_idx += 1 new_route = Route() new_route.load = remove_route.load arc_list_1 = remove_arc_list[:] arc_list_2 = remove_arc_list[:] arc_list_1.insert(insert_arc_idx, arc_list_1.pop(remove_arc_idx)) del arc_list_2[remove_arc_idx] arc_list_2.insert(insert_arc_idx, [remove_arc[0], not remove_arc[1]]) cost1 = get_route_cost(arc_list_1) cost2 = get_route_cost(arc_list_2) if cost1 < cost2: new_route.required_arc_list = arc_list_1 new_route.cost = cost1 else: new_route.required_arc_list = arc_list_2 new_route.cost = cost2 # new_route.required_arc_list = arc_list new_route_list = route_list[:] new_route_list[remove_route_idx] = new_route new_solution = Solution() new_solution.route_list = new_route_list diff = new_route.cost - remove_route.cost # print('cost2', diff) new_solution.quality = solution.quality + diff # print(new_solution.quality, get_quality(new_route_list)) return new_solution