无人机任务分配传统算法

 robin-shaun/Multi-UAV-Task-Assignment-Benchmark: A Benchmark for Multi-UAV Task Allocation of an Extended Team Orienteering Problem (github.com)

yhzhu99/mtsp: 群体智能大作业:基于仿生群智算法的无人机任务分配 (多旅行商问题的求解) (github.com) 

一、思路

预先设置无人机数目,途径点,然后迭代计算总的最短路径,最后绘制结果图

二、代码

plot_util.py

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签SimHei
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

# from matplotlib import colors as mcolors

# matplotlib_colors = list(dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS).keys())

matplotlib_colors = [
    "black",
    "red",
    "yellow",
    "grey",
    "brown",
    "darkred",
    "peru",
    "darkorange",
    "darkkhaki",
    "steelblue",
    "blue",
    "cyan",
    "green",
    "navajowhite",
    "lightgrey",
    "lightcoral",
    "mediumblue",
    "midnightblue",
    "blueviolet",
    "violet",
    "fuchsia",
    "mediumvioletred",
    "hotpink",
    "crimson",
    "lightpink",
    "slategray",
    "lime",
    "springgreen",
    "teal",
    "beige",
    "olive",
]


def find_indices(list_to_check, item_to_find):
    indices = []
    for idx, value in enumerate(list_to_check):
        if np.array_equal(value, item_to_find):
            indices.append(idx)
    return indices


def plot_results(Best_path, iterations, best_record):
    # print(find_indices(Best_path, [0, 0]))

    # Best_path = np.vstack([Best_path, Best_path[0]])
    # Best_path = np.vstack([Best_path[0], Best_path])
    # print(Best_path[0], Best_path[-1])

    if not np.array_equal(Best_path[0], [0, 0]):
        Best_path = np.vstack([[0, 0], Best_path])
    if not np.array_equal(Best_path[-1], [0, 0]):
        Best_path = np.vstack([Best_path, [0, 0]])
    #print(Best_path)

    found_start_points_indices = find_indices(Best_path, [0, 0])
    result_paths = []

    for j in range(len(found_start_points_indices) - 1):
        from_index = found_start_points_indices[j]
        end_index = found_start_points_indices[j + 1]
        path = []
        for k in range(from_index, end_index + 1):
            path.append(Best_path[k])
        path = np.array(path)
        result_paths.append(path)

    # print(Best_path)
    #print(result_paths)

    fig, axs = plt.subplots(1, 2, sharex=False, sharey=False)
    axs[0].scatter(Best_path[:, 0], Best_path[:, 1],c='r') #绘制点

    for ix, path in enumerate(result_paths): #result_paths包含不同无人机的路线
        axs[0].plot(path[:, 0], path[:, 1], color=matplotlib_colors[ix], alpha=1.0)
    # axs[0].plot(Best_path[:, 0], Best_path[:, 1], color="green", alpha=0.1)

    # Draw start point 绘制起点
    axs[0].plot([0], [0], marker="*", markersize=20, color="red")

    axs[0].set_title("最佳搜索结果")

    axs[1].plot(iterations, best_record)
    axs[1].set_title("Convergence Curve 收敛曲线")
    plt.show()

 aco.py

import math
import matplotlib.pyplot as plt
import numpy as np

import plot_util

#蚁群算法

class ACO(object):
    def __init__(self, num_city, data, num_drones):
        self.m = 50  # 蚂蚁数量
        self.alpha = 1  # 信息素重要程度因子
        self.beta = 5  # 启发函数重要因子
        self.rho = 0.1  # 信息素挥发因子
        self.Q = 1  # 常量系数
        self.num_city = num_city  # 城市规模
        self.num_drones = num_drones  # 有多少架无人机参与任务
        self.location = data  # 城市坐标
        self.Tau = np.zeros([num_city, num_city])  # 信息素矩阵
        self.Table = [[0 for _ in range(num_city)] for _ in range(self.m)]  # 生成的蚁群
        self.iter = 1
        self.dis_mat = self.compute_dis_mat(num_city, self.location)  # 计算城市之间的距离矩阵
        self.Eta = 10.0 / self.dis_mat  # 启发式函数
        self.paths = None  # 蚁群中每个个体的长度
        # 存储存储每个温度下的最终路径,画出收敛图
        self.iter_x = []
        self.iter_y = []

        # self.start_points_idx = []
        # self.greedy_init(self.dis_mat,100,num_city)

    def greedy_init(self, dis_mat, num_total, num_city):
        start_index = 0
        result = []
        for i in range(num_total):
            rest = [x for x in range(0, num_city)]
            # 所有起始点都已经生成了
            if start_index >= num_city:
                start_index = np.random.randint(0, num_city)
                result.append(result[start_index].copy())
                continue
            current = start_index
            rest.remove(current)
            # 找到一条最近邻路径
            result_one = [current]
            while len(rest) != 0:
                tmp_min = math.inf
                tmp_choose = -1
                for x in rest:
                    if dis_mat[current][x] < tmp_min:
                        tmp_min = dis_mat[current][x]
                        tmp_choose = x

                current = tmp_choose
                result_one.append(tmp_choose)
                rest.remove(tmp_choose)
            result.append(result_one)
            start_index += 1
        pathlens = self.compute_paths(result)
        sortindex = np.argsort(pathlens)
        index = sortindex[0]
        result = result[index]
        for i in range(len(result) - 1):
            s = result[i]
            s2 = result[i + 1]
            self.Tau[s][s2] = 1
        self.Tau[result[-1]][result[0]] = 1
        # for i in range(num_city):
        #     for j in range(num_city):
        # return result

    # 轮盘赌选择
    def rand_choose(self, p):
        x = np.random.rand()
        for i, t in enumerate(p):
            x -= t
            if x <= 0:
                break
        return i

    # 生成蚁群
    def get_ants(self, num_city):
        for i in range(self.m):
            start = np.random.randint(num_city - 1)
            self.Table[i][0] = start
            unvisit = list([x for x in range(num_city) if x != start])
            current = start
            j = 1
            while len(unvisit) != 0:
                P = []
                # 通过信息素计算城市之间的转移概率
                for v in unvisit:
                    P.append(
                        self.Tau[current][v] ** self.alpha
                        * self.Eta[current][v] ** self.beta
                    )
                P_sum = sum(P)
                P = [x / P_sum for x in P]
                # 轮盘赌选择一个一个城市
                index = self.rand_choose(P)
                current = unvisit[index]
                self.Table[i][j] = current
                unvisit.remove(current)
                j += 1

    # 关键: 修改distance matrix,适配多旅行商问题

    # 计算不同城市之间的距离
    def compute_dis_mat(self, num_city, location):
        # print("Location:", location)

        dis_mat = np.zeros((num_city, num_city))
        for i in range(num_city):
            for j in range(num_city):
                if i == j:
                    dis_mat[i][j] = np.inf
                    continue
                a = location[i]
                b = location[j]
                tmp = np.sqrt(sum([(x[0] - x[1]) ** 2 for x in zip(a, b)]))
                dis_mat[i][j] = tmp

        # self.start_points_idx = to_process_idx

        # print("to process indices:", to_process_idx)
        for i in to_process_idx:
            for j in to_process_idx:
                # print("processing:", i, j, dis_mat[i][j])
                dis_mat[i][j] = np.inf

        return dis_mat

    # 计算一条路径的长度
    def compute_pathlen(self, tmp_path, dis_mat):

        # print("Start!!!")

        path = tmp_path.copy()
        if path[0] not in to_process_idx:
            path.insert(0, 0)

        if path[-1] not in to_process_idx:
            path.append(0)

        a = path[0]
        b = path[-1]

        result = dis_mat[a][b]  # 首末城市之间的距离
        if a in to_process_idx and b in to_process_idx:
            result = 0
        for i in range(len(path) - 1):
            a = path[i]
            b = path[i + 1]
            if a in to_process_idx and b in to_process_idx:
                result += 0
            else:
                result += dis_mat[a][b]
        # 关键:此时,原点-原点的距离不再是inf,而是0
        # print("End!!!")

        return result

    # 计算一个群体的长度
    def compute_paths(self, paths):
        result = []
        for one in paths:
            length = self.compute_pathlen(one, self.dis_mat)
            result.append(length)
        return result

    # 更新信息素
    def update_Tau(self):
        delta_tau = np.zeros([self.num_city, self.num_city])
        paths = self.compute_paths(self.Table)
        for i in range(self.m):
            for j in range(self.num_city - 1):
                a = self.Table[i][j]
                b = self.Table[i][j + 1]
                delta_tau[a][b] = delta_tau[a][b] + self.Q / paths[i]
            a = self.Table[i][0]
            b = self.Table[i][-1]
            delta_tau[a][b] = delta_tau[a][b] + self.Q / paths[i]
        self.Tau = (1 - self.rho) * self.Tau + delta_tau

    def aco(self):
        best_lenth = math.inf
        best_path = None
        early_stop_cnt = 0
        for cnt in range(epochs):
            # 生成新的蚁群
            self.get_ants(self.num_city)  # out>>self.Table
            self.paths = self.compute_paths(self.Table)
            # 取该蚁群的最优解
            tmp_lenth = min(self.paths)
            tmp_path = self.Table[self.paths.index(tmp_lenth)]
            # 可视化初始的路径
            if cnt == 0:
                init_show = self.location[tmp_path]
                init_show = np.vstack([init_show, init_show[0]])
            # 更新最优解
            if tmp_lenth < best_lenth:
                best_lenth = tmp_lenth
                best_path = tmp_path
                early_stop_cnt = 0
            else:
                early_stop_cnt += 1
            if early_stop_cnt == 20:  # 若连续20次没有性能提升,则早停
                break

            # 更新信息素
            self.update_Tau()

            # 保存结果
            self.iter_x.append(cnt)
            self.iter_y.append(best_lenth)
            print(f"Epoch {cnt:3}   最短路径:{best_lenth:.3f}")
            #print(best_path)
        return best_lenth, best_path

    def run(self):
        best_length, best_path = self.aco()
        return self.location[best_path], best_length


seed = 42
num_drones = 30 #无人机数目
num_city = 30  #需要遍历的目标点数目
epochs = 100   #迭代次数

# 固定随机数
np.random.seed(seed)


## 初始化坐标 (第一个点是基地的起点,起点的坐标是 0,0 )
data = [[0, 0]]  #点集合,城市位置
for i in range(num_city - 1):
    while True:
        x = np.random.randint(-250, 250)#随机生成途径点的x,y
        y = np.random.randint(-250, 250)
        if x != 0 or y != 0:
            break
    data.append([x, y])
    print("途径点坐标:", data[i])

data = np.array(data)

# print(data, data.shape)

# 关键:有N架无人机,则再增加N-1个`点` (坐标是起始点),这些点之间的距离是inf
for d in range(num_drones - 1):
    data = np.vstack([data, data[0]]) #按垂直方向(行顺序)堆叠数组构成一个新的数组
    num_city += 1  # 增加欺骗城市

to_process_idx = [0]
# print("start point:", location[0])
for d in range(1, num_drones):  # 1, ... drone-1
    # print("added base point:", location[num_city - d])
    to_process_idx.append(num_city - d)

# print(data)

# print("City len assert:", num_city, data.shape[0])

# print(show_data, show_data.shape)

aco = ACO(num_city=data.shape[0], data=data.copy(), num_drones=num_drones) #城市位置  无人机数
Best_path, Best = aco.run()
iterations = aco.iter_x   #迭代次数
best_record = aco.iter_y  #每次迭代对应的最短路径,用来绘制收敛曲线

print(f"Best Path Length: {Best:.3f}  Best_path:{Best_path} ") #\n iter_x:{iterations}  \n iter_y:{best_record}")
plot_util.plot_results(Best_path, iterations, best_record)#

 pso.py

import math
import random

import matplotlib.pyplot as plt
import numpy as np

import plot_util


class PSO(object):
    def __init__(self, num_city, data):
        self.num = 200  # 粒子数目
        self.num_city = num_city  # 城市数
        self.location = data  # 城市的位置坐标
        # 计算距离矩阵
        self.dis_mat = self.compute_dis_mat(num_city, self.location)  # 计算城市之间的距离矩阵
        # 初始化所有粒子
        self.particals = self.random_init(self.num, num_city)
        # self.particals = self.greedy_init(
        #     self.dis_mat, num_total=self.num, num_city=num_city
        # )
        self.lenths = self.compute_paths(self.particals)
        # 得到初始化群体的最优解
        init_l = min(self.lenths)
        init_index = self.lenths.index(init_l)
        init_path = self.particals[init_index]
        # 画出初始的路径图
        init_show = self.location[init_path]
        # 记录每个个体的当前最优解
        self.local_best = self.particals
        self.local_best_len = self.lenths
        # 记录当前的全局最优解,长度是iteration
        self.global_best = init_path
        self.global_best_len = init_l
        # 输出解
        self.best_l = self.global_best_len
        self.best_path = self.global_best
        # 存储每次迭代的结果,画出收敛图
        self.iter_x = [0]
        self.iter_y = [init_l]

    def greedy_init(self, dis_mat, num_total, num_city):
        start_index = 0
        result = []
        for i in range(num_total):
            rest = [x for x in range(0, num_city)]
            # 所有起始点都已经生成了
            if start_index >= num_city:
                start_index = np.random.randint(0, num_city)
                result.append(result[start_index].copy())
                continue
            current = start_index
            rest.remove(current)
            # 找到一条最近邻路径
            result_one = [current]
            while len(rest) != 0:
                tmp_min = math.inf
                tmp_choose = -1
                for x in rest:
                    # print("---", current, x, dis_mat[current][x])
                    if dis_mat[current][x] < tmp_min:
                        tmp_min = dis_mat[current][x]
                        tmp_choose = x
                if tmp_choose == -1:  # 此种情况仅可能发生在剩的都是基地点
                    tmp_choose = rest[0]
                    # print("tmp_choose:", tmp_choose)
                current = tmp_choose
                result_one.append(tmp_choose)
                # print(current, rest)
                rest.remove(tmp_choose)
                # print(rest)
            result.append(result_one)
            start_index += 1
        # print(len(result), len(result[0]))
        return result

    # 随机初始化
    def random_init(self, num_total, num_city):
        tmp = [x for x in range(num_city)]
        result = []
        for i in range(num_total):
            random.shuffle(tmp)
            result.append(tmp.copy())
        return result

    # 计算不同城市之间的距离
    def compute_dis_mat(self, num_city, location):
        dis_mat = np.zeros((num_city, num_city))
        for i in range(num_city):
            for j in range(num_city):
                if i == j:
                    dis_mat[i][j] = np.inf
                    continue
                a = location[i]
                b = location[j]
                tmp = np.sqrt(sum([(x[0] - x[1]) ** 2 for x in zip(a, b)]))
                dis_mat[i][j] = tmp

        for i in to_process_idx:
            for j in to_process_idx:
                # print("processing:", i, j, dis_mat[i][j])
                dis_mat[i][j] = np.inf

        return dis_mat

    # 计算路径长度
    def compute_pathlen(self, tmp_path, dis_mat):
        path = tmp_path.copy()
        if path[0] not in to_process_idx:
            path.insert(0, 0)

        if path[-1] not in to_process_idx:
            path.append(0)

        try:
            a = path[0]
            b = path[-1]
        except:
            import pdb

            pdb.set_trace()

        result = dis_mat[a][b]  # 首末城市之间的距离
        if a in to_process_idx and b in to_process_idx:
            result = 0

        for i in range(len(path) - 1):
            a = path[i]
            b = path[i + 1]
            if a in to_process_idx and b in to_process_idx:
                result += 0
            else:
                result += dis_mat[a][b]
        return result

    # 计算一个群体的长度
    def compute_paths(self, paths):
        result = []
        for one in paths:
            length = self.compute_pathlen(one, self.dis_mat)
            result.append(length)
        return result

    # 评估当前的群体
    def eval_particals(self):
        min_lenth = min(self.lenths)
        min_index = self.lenths.index(min_lenth)
        cur_path = self.particals[min_index]
        # 更新当前的全局最优
        if min_lenth < self.global_best_len:
            self.global_best_len = min_lenth
            self.global_best = cur_path
        # 更新当前的个体最优
        for i, l in enumerate(self.lenths):
            if l < self.local_best_len[i]:
                self.local_best_len[i] = l
                self.local_best[i] = self.particals[i]

    # 粒子交叉
    def cross(self, cur, best):
        one = cur.copy()
        l = [t for t in range(self.num_city)]
        t = np.random.choice(l, 2)
        x = min(t)
        y = max(t)
        cross_part = best[x:y]
        tmp = []
        for t in one:
            if t in cross_part:
                continue
            tmp.append(t)
        # 两种交叉方法
        one = tmp + cross_part
        l1 = self.compute_pathlen(one, self.dis_mat)
        one2 = cross_part + tmp
        l2 = self.compute_pathlen(one2, self.dis_mat)
        if l1 < l2:
            return one, l1
        else:
            return one, l2

    # 粒子变异
    def mutate(self, one):
        one = one.copy()
        l = [t for t in range(self.num_city)]
        t = np.random.choice(l, 2)
        x, y = min(t), max(t)
        one[x], one[y] = one[y], one[x]
        l2 = self.compute_pathlen(one, self.dis_mat)
        return one, l2

    # 迭代操作
    def pso(self):
        early_stop_cnt = 0
        for cnt in range(epochs):
            # 更新粒子群
            for i, one in enumerate(self.particals):
                tmp_l = self.lenths[i]
                # 与当前个体局部最优解进行交叉
                new_one, new_l = self.cross(one, self.local_best[i])
                if new_l < self.best_l:
                    self.best_l = tmp_l
                    self.best_path = one

                if new_l < tmp_l or np.random.rand() < 0.1:
                    one = new_one
                    tmp_l = new_l

                # 与当前全局最优解进行交叉
                new_one, new_l = self.cross(one, self.global_best)

                if new_l < self.best_l:
                    self.best_l = tmp_l
                    self.best_path = one

                if new_l < tmp_l or np.random.rand() < 0.1:
                    one = new_one
                    tmp_l = new_l
                # 变异
                one, tmp_l = self.mutate(one)

                if new_l < self.best_l:
                    self.best_l = tmp_l
                    self.best_path = one

                if new_l < tmp_l or np.random.rand() < 0.1:
                    one = new_one
                    tmp_l = new_l

                # 更新该粒子
                self.particals[i] = one
                self.lenths[i] = tmp_l
            # 评估粒子群,更新个体局部最优和个体当前全局最优
            self.eval_particals()
            # 更新输出解
            if self.global_best_len < self.best_l:
                self.best_l = self.global_best_len
                self.best_path = self.global_best
                early_stop_cnt = 0
            else:
                early_stop_cnt += 1
            if early_stop_cnt == 50:  # 若连续50次没有性能提升,则早停
                break
            print(f"Epoch {cnt:3}: {self.best_l:.3f}")
            self.iter_x.append(cnt)
            self.iter_y.append(self.best_l)
        return self.best_l, self.best_path

    def run(self):
        best_length, best_path = self.pso()
        # 画出最终路径
        return self.location[best_path], best_length


seed = 42
num_drones = 20
num_city = 100
epochs = 50

# 固定随机数
np.random.seed(seed)
random.seed(seed)


## 初始化坐标 (第一个点是基地的起点,起点的坐标是 0,0 )
data = [[0, 0]]
for i in range(num_city - 1):
    while True:
        x = np.random.randint(-250, 250)
        y = np.random.randint(-250, 250)
        if x != 0 or y != 0:
            break
    data.append([x, y])

data = np.array(data)

# 关键:有N架无人机,则再增加N-1个`点` (坐标是起始点),这些点之间的距离是inf
for d in range(num_drones - 1):
    data = np.vstack([data, data[0]])
    num_city += 1  # 增加欺骗城市

to_process_idx = [0]
for d in range(1, num_drones):  # 1, ... drone-1
    to_process_idx.append(num_city - d)

model = PSO(num_city=data.shape[0], data=data.copy())
Best_path, Best = model.run()

iterations = model.iter_x
best_record = model.iter_y

print(f"Best Path Length: {Best:.3f}")
plot_util.plot_results(Best_path, iterations, best_record)

ga.py 

import math
import random

import matplotlib.pyplot as plt
import numpy as np

import plot_util


class GA(object):
    def __init__(self, num_city, num_total, data):
        self.num_city = num_city
        self.num_total = num_total
        self.scores = []
        # self.iteration = iteration
        self.location = data
        self.ga_choose_ratio = 0.2
        self.mutate_ratio = 0.05
        # fruits中存每一个个体是下标的list
        self.dis_mat = self.compute_dis_mat(num_city, data)
        # self.fruits = self.greedy_init(self.dis_mat, num_total, num_city)
        self.fruits = self.random_init(num_total, num_city)
        # 显示初始化后的最佳路径
        scores = self.compute_adp(self.fruits)
        sort_index = np.argsort(-scores)
        init_best = self.fruits[sort_index[0]]
        init_best = self.location[init_best]

        # 存储每个iteration的结果,画出收敛图
        self.iter_x = [0]
        self.iter_y = [1.0 / scores[sort_index[0]]]

    def random_init(self, num_total, num_city):
        tmp = [x for x in range(num_city)]
        result = []
        for i in range(num_total):
            random.shuffle(tmp)
            result.append(tmp.copy())
        # print("Lens:", len(result), len(result[0]))
        return result

    def greedy_init(self, dis_mat, num_total, num_city):
        start_index = 0
        result = []
        for i in range(num_total):
            rest = [x for x in range(0, num_city)]
            # 所有起始点都已经生成了
            if start_index >= num_city:
                start_index = np.random.randint(0, num_city)
                result.append(result[start_index].copy())
                continue
            current = start_index
            rest.remove(current)
            # 找到一条最近邻路径
            result_one = [current]
            while len(rest) != 0:
                tmp_min = math.inf
                tmp_choose = -1
                for x in rest:
                    # print("---", current, x, dis_mat[current][x])
                    if dis_mat[current][x] < tmp_min:
                        tmp_min = dis_mat[current][x]
                        tmp_choose = x
                if tmp_choose == -1:  # 此种情况仅可能发生在剩的都是基地点
                    tmp_choose = rest[0]
                    # print("tmp_choose:", tmp_choose)
                current = tmp_choose
                result_one.append(tmp_choose)
                # print(current, rest)
                rest.remove(tmp_choose)
                # print(rest)
            result.append(result_one)
            start_index += 1
        # print(len(result), len(result[0]))
        return result

    # 计算不同城市之间的距离
    def compute_dis_mat(self, num_city, location):
        dis_mat = np.zeros((num_city, num_city))
        for i in range(num_city):
            for j in range(num_city):
                if i == j:
                    dis_mat[i][j] = np.inf
                    continue
                a = location[i]
                b = location[j]
                tmp = np.sqrt(sum([(x[0] - x[1]) ** 2 for x in zip(a, b)]))
                dis_mat[i][j] = tmp

        for i in to_process_idx:
            for j in to_process_idx:
                # print("processing:", i, j, dis_mat[i][j])
                dis_mat[i][j] = np.inf

        return dis_mat

    # 计算路径长度
    def compute_pathlen(self, tmp_path, dis_mat):
        path = tmp_path.copy()
        if path[0] not in to_process_idx:
            path.insert(0, 0)

        if path[-1] not in to_process_idx:
            path.append(0)

        try:
            a = path[0]
            b = path[-1]
        except:
            import pdb

            pdb.set_trace()

        result = dis_mat[a][b]  # 首末城市之间的距离
        if a in to_process_idx and b in to_process_idx:
            result = 0

        for i in range(len(path) - 1):
            a = path[i]
            b = path[i + 1]
            if a in to_process_idx and b in to_process_idx:
                result += 0
            else:
                result += dis_mat[a][b]
        return result

    # 计算种群适应度
    def compute_adp(self, fruits):
        adp = []
        for fruit in fruits:
            if isinstance(fruit, int):
                import pdb

                pdb.set_trace()
            length = self.compute_pathlen(fruit, self.dis_mat)
            adp.append(1.0 / length)
        return np.array(adp)

    def swap_part(self, list1, list2):
        index = len(list1)
        list = list1 + list2
        list = list[::-1]
        return list[:index], list[index:]

    def ga_cross(self, x, y):
        len_ = len(x)
        assert len(x) == len(y)
        path_list = [t for t in range(len_)]
        order = list(random.sample(path_list, 2))
        order.sort()
        start, end = order

        # 找到冲突点并存下他们的下标,x中存储的是y中的下标,y中存储x与它冲突的下标
        tmp = x[start:end]
        x_conflict_index = []
        for sub in tmp:
            index = y.index(sub)
            if not (index >= start and index < end):
                x_conflict_index.append(index)

        y_confict_index = []
        tmp = y[start:end]
        for sub in tmp:
            index = x.index(sub)
            if not (index >= start and index < end):
                y_confict_index.append(index)

        assert len(x_conflict_index) == len(y_confict_index)

        # 交叉
        tmp = x[start:end].copy()
        x[start:end] = y[start:end]
        y[start:end] = tmp

        # 解决冲突
        for index in range(len(x_conflict_index)):
            i = x_conflict_index[index]
            j = y_confict_index[index]
            y[i], x[j] = x[j], y[i]

        assert len(set(x)) == len_ and len(set(y)) == len_
        return list(x), list(y)

    def ga_parent(self, scores, ga_choose_ratio):
        sort_index = np.argsort(-scores).copy()
        sort_index = sort_index[0 : int(ga_choose_ratio * len(sort_index))]
        parents = []
        parents_score = []
        for index in sort_index:
            parents.append(self.fruits[index])
            parents_score.append(scores[index])
        return parents, parents_score

    def ga_choose(self, genes_score, genes_choose):
        sum_score = sum(genes_score)
        score_ratio = [sub * 1.0 / sum_score for sub in genes_score]
        rand1 = np.random.rand()
        rand2 = np.random.rand()
        index1, index2 = 0, 0
        for i, sub in enumerate(score_ratio):
            if rand1 >= 0:
                rand1 -= sub
                if rand1 < 0:
                    index1 = i
            if rand2 >= 0:
                rand2 -= sub
                if rand2 < 0:
                    index2 = i
            if rand1 < 0 and rand2 < 0:
                break
        return list(genes_choose[index1]), list(genes_choose[index2])

    def ga_mutate(self, gene):
        path_list = [t for t in range(len(gene))]
        order = list(random.sample(path_list, 2))
        start, end = min(order), max(order)
        tmp = gene[start:end]
        # np.random.shuffle(tmp)
        tmp = tmp[::-1]
        gene[start:end] = tmp
        return list(gene)

    def ga(self):
        # 获得优质父代
        scores = self.compute_adp(self.fruits)
        # 选择部分优秀个体作为父代候选集合
        parents, parents_score = self.ga_parent(scores, self.ga_choose_ratio)
        tmp_best_one = parents[0]
        tmp_best_score = parents_score[0]
        # 新的种群fruits
        fruits = parents.copy()
        # 生成新的种群
        while len(fruits) < self.num_total:
            # 轮盘赌方式对父代进行选择
            gene_x, gene_y = self.ga_choose(parents_score, parents)
            # 交叉
            gene_x_new, gene_y_new = self.ga_cross(gene_x, gene_y)
            # 变异
            if np.random.rand() < self.mutate_ratio:
                gene_x_new = self.ga_mutate(gene_x_new)
            if np.random.rand() < self.mutate_ratio:
                gene_y_new = self.ga_mutate(gene_y_new)
            x_adp = 1.0 / self.compute_pathlen(gene_x_new, self.dis_mat)
            y_adp = 1.0 / self.compute_pathlen(gene_y_new, self.dis_mat)
            # 将适应度高的放入种群中
            if x_adp > y_adp and (not gene_x_new in fruits):
                fruits.append(gene_x_new)
            elif x_adp <= y_adp and (not gene_y_new in fruits):
                fruits.append(gene_y_new)

        self.fruits = fruits

        return tmp_best_one, tmp_best_score

    def run(self):
        BEST_LIST = None
        best_score = -math.inf
        self.best_record = []
        early_stop_cnt = 0
        for i in range(epochs):
            tmp_best_one, tmp_best_score = self.ga()
            self.iter_x.append(i)
            self.iter_y.append(1.0 / tmp_best_score)
            if tmp_best_score > best_score:
                best_score = tmp_best_score
                BEST_LIST = tmp_best_one
                early_stop_cnt = 0
            else:
                early_stop_cnt += 1
            if early_stop_cnt == 50:  # 若连续50次没有性能提升,则早停
                break
            self.best_record.append(1.0 / best_score)
            best_length = 1.0 / best_score
            print(f"Epoch {i:3}: {best_length:.3f}")
        # print(1.0 / best_score)
        return self.location[BEST_LIST], 1.0 / best_score


seed = 42
num_drones = 30
num_city = 50
epochs = 30

# 固定随机数
np.random.seed(seed)
random.seed(seed)


## 初始化坐标 (第一个点是基地的起点,起点的坐标是 0,0 )
data = [[0, 0]]
for i in range(num_city - 1):
    while True:
        x = np.random.randint(-250, 250)
        y = np.random.randint(-250, 250)
        if x != 0 or y != 0:
            break
    data.append([x, y])

data = np.array(data)

# 关键:有N架无人机,则再增加N-1个`点` (坐标是起始点),这些点之间的距离是inf
for d in range(num_drones - 1):
    data = np.vstack([data, data[0]])
    num_city += 1  # 增加欺骗城市

to_process_idx = [0]
# print("start point:", location[0])
for d in range(1, num_drones):  # 1, ... drone-1
    # print("added base point:", location[num_city - d])
    to_process_idx.append(num_city - d)

model = GA(num_city=data.shape[0], num_total=20, data=data.copy())
Best_path, Best = model.run()
# print(Best_path)
iterations = model.iter_x
best_record = model.iter_y

# print(Best_path)

print(f"Best Path Length: {Best:.3f}")
plot_util.plot_results(Best_path, iterations, best_record)

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
蒙特卡洛算法可以用于无人机任务分配的优化。在无人机任务分配中,我们需要将多个任务分配给多台无人机,以实现最优的任务执行效果。 蒙特卡洛算法是一种随机模拟方法,通过重复随机抽样来估计问题的解。在无人机任务分配中,可以使用蒙特卡洛算法来模拟不同的任务分配方案,并评估每种方案的效果。 具体来说,可以按照以下步骤应用蒙特卡洛算法进行无人机任务分配: 1. 定义问题:明确任务和无人机的约束条件,例如任务数量、无人机数量、任务属性等。 2. 随机生成初始解:随机分配任务给无人机,得到一个初始的分配方案。 3. 评估方案:根据预先设定的评估指标,对每个无人机的任务执行情况进行评估,例如任务完成时间、能源消耗等。 4. 生成新解:利用某种策略,例如随机交换两个任务的分配或者随机重新分配所有任务,生成新的分配方案。 5. 评估新解:对新生成的分配方案进行评估。 6. 更新当前解:根据一定的概率规则,确定是否接受新解作为当前解。如果新解优于当前解,直接接受;如果新解劣于当前解,以一定概率接受。 7. 重复步骤4-6,直到达到停止准则(例如迭代次数达到上限或者运行时间超过限制)。 8. 输出最优解:根据蒙特卡洛模拟的结果,输出最优的任务分配方案。 需要注意的是,蒙特卡洛算法是一种启发式方法,不能保证找到全局最优解。因此,在实际应用中,可以进行多次独立的蒙特卡洛模拟,并从中选取最优的任务分配方案。此外,还可以结合其他优化方法进行进一步改进,以提高任务分配的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aspiretop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值