算法调研
现在的导航系统,仅有固定的a点到b点之间的单源导航,就算是增加途径点,本质上也是单源的路径规划算法。
但是针对货车场景,货车司机经常需要从多个仓库上货,中间又穿插着多个目标地点下货。针对该场景,传统的导航方式将无法完成任务。
适用于单个车辆的多仓库、多目标路径规划的两种有效算法:遗传算法和蚁群算法。
遗传算法(Genetic Algorithm, GA):
遗传算法是一种优化算法,灵感来自于生物进化的过程。
在单个车辆的多仓库、多目标路径规划中,遗传算法可以用于搜索最优的路径组合。
基本思想:
- 创建一个初始种群,每个个体表示一种路径规划方案。
- 通过选择、交叉和变异操作,不断优化种群中的个体。
- 逐代迭代,直到找到最优解或达到停止条件。
适用性:
遗传算法适用于复杂的路径规划问题,可以处理多个仓库、多个目标点,以及不同的约束条件(如车辆容量、时间窗口等)。
蚁群算法(Ant Colony Optimization, ACO):
蚁群算法模拟了蚂蚁在寻找食物时的行为。
在单个车辆的多仓库、多目标路径规划中,蚁群算法可以用于搜索最短路径。
基本思想:
- 创建一群虚拟蚂蚁,每只蚂蚁代表一种路径规划。
- 蚂蚁根据信息素浓度选择路径,同时释放信息素。
- 信息素浓度会影响其他蚂蚁的选择,从而逐步优化路径。
适用性:
蚁群算法适用于具有多个目标点的复杂环境,可以处理多仓库、多目标点的路径规划问题。
蚁群算法思路考虑
针对遗传算法构建python代码.需要注意的规则如下:
- 必须保证货车先去仓库,再去目标地点;
- 必须保证所有的货物容量和重量不会超出车辆容量和限重。
- 输入为仓库坐标和目标坐标的二元列表的列表,例如[[仓库1,目标1,体积1,重量1],[仓库1,目标2,体积2,重量2],[仓库2,目标1,体积3,重量3],[仓库2,目标2,体积4,重量4],[仓库3,目标3,体积5,重量5]]
伪代码如下:
初始化算法参数和信息素矩阵
设置起始点坐标
初始化仓库和目标的货物状态
for 迭代次数 in 范围(最大迭代次数):
蚂蚁列表 = []
for 蚂蚁 in 范围(蚂蚁数量):
当前蚂蚁 = 初始化蚂蚁(起始点坐标)
当前蚂蚁的路径 = []
当前蚂蚁的装载状态 = 初始化装载状态
while 仍有未送达的货物:
下一个节点 = 当前蚂蚁选择下一个节点(根据信息素和启发式信息)
当前蚂蚁的路径.append(下一个节点)
if 下一个节点是仓库:
加载货物到当前蚂蚁(根据剩余容量)
更新当前蚂蚁的装载状态
elif 下一个节点是目标:
卸载货物从当前蚂蚁(根据目标需求量)
更新当前蚂蚁的装载状态
if 所有货物已送达:
break
蚂蚁列表.append(当前蚂蚁)
评估所有蚂蚁的路径并计算总时间
更新信息素矩阵
if 所有货物已送达:
break
输出最佳蚂蚁的路径和总时间
主文件如下:
import numpy as np
import function
import time
# 初始化算法参数
num_ants = 10 # 蚂蚁数量
max_iterations = 20 # 最大迭代次数
evaporation_rate = 0.3 # 信息素挥发率(上一轮的信息素在下一轮中的挥发比例)
max_volume = 50 # 最大容量
max_weight = 50 # 最大载重
start_point = np.array([0, 0]) # 设置起始点坐标
delt_time = 10
best_ant = []
best_time = []
node_list = [ # 节点坐标列表
np.array([0, 0]),
np.array([1, 4]),
np.array([2, 4]),
np.array([4, 6]),
np.array([1, 8]),
np.array([6, 10]),
np.array([5, 12])
]
# 初始化仓库和目标的货物状态 [仓库节点id, 目标节点id, 体积, 重量]
warehouse_targets = [
[1, 2, 5, 10],
[2, 3, 8, 15],
[3, 4, 6, 12],
[4, 5, 7, 8],
[5, 6, 9, 7],
[1, 4, 5, 8],
[2, 5, 7, 10],
[3, 6, 4, 6]
]
# 初始化信息素矩阵启发式信息矩阵
num_points = len(node_list) # 仓库和目标地点总数
pheromone_matrix = np.ones((num_points, num_points)) # 信息素矩阵
heuristic_matrix = function.calculate_inverse_distance_matrix(node_list)# 启发式信息矩阵
# 初始化蚂蚁列表
ants = [function.Ant(start_point, node_list) for _ in range(num_ants)]
# 主循环
for iteration in range(max_iterations):
# 重新初始化蚂蚁列表
ants = [function.Ant(start_point, node_list) for _ in range(num_ants)]
# 评估路径总时间
total_time = 0
count = 0
for ant in ants:
count = count + 1
# 初始化货物送达状态
delivered = {i: False for i in range(len(warehouse_targets))}
# 蚂蚁送货
while not all(delivered.values()):
print("#####################")
#time.sleep(0.5)
# 蚂蚁选择下一个节点
next_node = ant.select_next_node(pheromone_matrix, heuristic_matrix, node_list, warehouse_targets, delivered)
# 更新当前蚂蚁的位置
ant.current_point = node_list[next_node]
action = ""
# 如果下一个节点是仓库
if any((next_node == wt[0]).all() for wt in warehouse_targets):
# 加载货物到当前蚂蚁
for index, wt in enumerate(warehouse_targets):
# 若为仓库,且(仓库货物不在车辆上且没有抵达)则上货
if (next_node == wt[0]).all() and index not in ant.current_cargo and delivered[index] == False:
if ant.load_weight + wt[3] <= max_weight and ant.load_volume + wt[2] <= max_volume:
print(wt, "上货")
ant.load_weight += wt[3]
ant.load_volume += wt[2]
ant.current_cargo.append(index)
action = action + "上货" + str(index) + "号货物"
# 如果下一个节点是目标地点
if any((next_node == wt[1]).all() for wt in warehouse_targets):
# 卸载货物从当前蚂蚁
for index, wt in enumerate(warehouse_targets):
if next_node == wt[1] and index in ant.current_cargo:
print(wt, "卸货")
ant.load_weight -= wt[3]
ant.load_volume -= wt[2]
ant.current_cargo.remove(index)
delivered[index] = True
action = action + "卸货" + str(index) + "号货物"
if all(delivered.values()):
print("货物抵达情况:", delivered)
break
# 更新路径
ant.path.append([next_node, action])
# 如果所有货物已送达,退出循环
if all(delivered.values()):
print("货物抵达情况:", delivered)
break
ant.print_status()
print("货物抵达情况:", delivered)
# 计算蚂蚁的路径总时间
ant_time = function.get_cost(ant, delt_time, node_list)
total_time += ant_time
# 输出最佳蚂蚁的路径和总时间
best_ant_temp, best_time_temp = function.get_best_ant(ants, delt_time, node_list)
best_ant.append([best_ant_temp, best_time_temp])
# 更新信息素
delta_pheromone = np.zeros((num_points, num_points))
for ant in ants:
ant_cost = function.get_cost(ant, delt_time, node_list)
# 精英算法,只有足够优异的蚂蚁有资格留下信息素
if ant_cost > 130:
continue
for i in range(len(ant.path) - 1):
delta_pheromone[ant.path[i][0]][ant.path[i + 1][0]] += 200 / total_time
pheromone_matrix = (1 - evaporation_rate) * pheromone_matrix + delta_pheromone
# 输出最佳蚂蚁的路径和总时间
Best_ant = sorted(best_ant, key=lambda x: x[1])
best_path = Best_ant[0][0].path
print("Best Path:", best_path)
print("Total Time:", Best_ant[0][1])
次文件function.py如下:
import numpy as np
def calculate_inverse_distance_matrix(node_list):
"""
计算节点列表中每个点到其他所有点之间距离的倒数,并返回一个距离倒数矩阵。
参数:
node_list (list of np.ndarray): 包含节点坐标的列表,每个节点坐标是一个 NumPy 数组。
返回:
np.ndarray: 距离倒数矩阵,大小为 (len(node_list), len(node_list))。
"""
# 初始化距离矩阵
num_nodes = len(node_list)
distance_matrix = np.zeros((num_nodes, num_nodes))
# 计算距离并存储倒数
for i in range(num_nodes):
for j in range(i+1, num_nodes): # 只计算i到j,避免重复计算
distance = calculate_distance(node_list[i], node_list[j]) # 计算两点间距离
if distance > 0: # 避免除以0的情况
distance_inverse = 1.0 / distance
distance_matrix[i, j] = distance_inverse
distance_matrix[j, i] = distance_inverse # 距离矩阵对称
return distance_matrix
# 计算两点之间的距离时间 后续需要用导航API替代
def calculate_distance(point1, point2):
return np.linalg.norm(point1 - point2)
# 定义蚂蚁类
class Ant:
def __init__(self, start_point, node_list):
self.current_point = start_point # 当前位置
self.path = [[0,"出发!"]] # 已经过的路径与操作
self.current_cargo = [] # 装载的货物id
self.load_volume = 0 # 已有容量
self.load_weight = 0 # 已有重量
def select_next_node(self, pheromone_matrix, heuristic_matrix, node_list, warehouse_targets, delivered):
"""
根据信息素和启发式信息选择下一个节点
:param pheromone_matrix: 信息素矩阵
:param heuristic_matrix: 启发式信息矩阵(如距离的倒数)
:return: 选择的下一个节点的索引
"""
# 获取当前节点在notelist中的索引
current_node_index = next((i for i, arr in enumerate(node_list) if np.array_equal(arr, self.current_point)), None)
# 计算选择下一个节点的概率
probabilities = []
for i, node_index in enumerate(range(len(pheromone_matrix))):
# 需要上货
need_to_load = False
# 需要卸货
need_to_down = False
for j, wt in enumerate(warehouse_targets):
# 若为仓库
if node_index == wt[0] and j not in self.current_cargo and delivered[j] == False:
print(node_index, "是仓库,需要上货", j, "号货物")
need_to_load = True
if node_index == wt[1] and j in self.current_cargo:
print(node_index, "是目标,需要卸货", j, "号货物")
need_to_down = True
if need_to_down == False and need_to_load == False:
probabilities.append(0.0)
continue
if pheromone_matrix[current_node_index, node_index] == 0:
# 跳过信息素为0的节点
probabilities.append(0.0)
else:
# 计算选择概率,通常使用信息素和启发式信息的某种组合
# 这里简化地假设为信息素和启发式信息的乘积
prob = pheromone_matrix[current_node_index, node_index] * heuristic_matrix[current_node_index, node_index]
probabilities.append(prob)
# 归一化概率
probabilities = [p / sum(probabilities) for p in probabilities]
# 根据概率随机选择下一个节点
next_node_index = np.random.choice(range(len(probabilities)), p=probabilities)
return next_node_index
def print_status(self):
print("当前位置:", self.current_point)
print("当前载重:", self.load_weight)
print("当前体积:", self.load_volume)
print("装载的货物ID列表", self.current_cargo)
print("经过路径:", self.path)
# 获取当前蚂蚁的代价
def get_cost(ant, delt_time, node_list):
ant_time = 0
for i in range(len(ant.path) - 1):
# 模拟时间:简单地取两点之间的距离作为时间
distance = calculate_distance(node_list[ant.path[i][0]], node_list[ant.path[i+1][0]])
#计算 运货时间 and 上下货时间
ant_time += distance + delt_time
return ant_time
# 获取最佳蚂蚁
def get_best_ant(ants, delt_time, node_list):
min_cost = 999
best_ant = None
for ant in ants:
ant_time = get_cost(ant, delt_time, node_list)
if ant_time < min_cost:
min_cost = ant_time
best_ant = ant
print("ant.time = ", ant_time)
return best_ant, min_cost
# 更新信息素矩阵
def refresh_pheromone_matrix(ants, pheromone_matrix):
return