# 基于蚁群算法的多机械臂取苗问题
import numpy as np
import random
import math
import copy
import matplotlib.pyplot as plt
import time
import sys
import os
# 添加父目录到搜索路径
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(parent_dir)
from class_common_function import common_function
plt.rcParams['font.sans-serif'] = ['SimHei']
class AntColonyOptimization:
def __init__(self, x_num, y_num, empty_num, num_ants=100, alpha=1, beta=5, evaporation_rate=0.5, Q=100, random_seed=1):
# 初始化算法参数和问题数据
if random_seed is not None:
random.seed(random_seed)
np.random.seed(random_seed)
self.num_ants = num_ants
self.alpha = alpha
self.beta = beta
self.evaporation_rate = evaporation_rate
self.Q = Q
self.common_func = common_function(x_num=x_num, y_num=y_num, empty_num=empty_num)
self.x_num = self.common_func.x_num
self.y_num = self.common_func.y_num
self.positions = self.common_func.positions
self.exist_position = self.common_func.exist_position
self.target_need_number = self.common_func.target_need_number
self.supply_need_number = self.common_func.supply_need_number
self.empty_num = self.common_func.empty_num
self.target_state = self.common_func.target_state
self.supply_state = self.common_func.supply_state
self.supply_order_array = self.common_func.supply_order_array
self.target_order_array = self.common_func.target_order_array
self.num_points = len(self.positions)
self.distance_matrix, self.max_distance, self.min_distance= self.calc_distance_matrix()
self.pheromone_matrix = np.ones((self.num_points, self.num_points))
self.best_path = []
self.best_fitness = 0
def calc_distance_matrix(self):
# 计算所有点之间的欧几里得距离矩阵
num_points = self.num_points
distance_matrix = np.zeros((num_points, num_points))
for i in range(num_points):
for j in range(num_points):
distance_matrix[i][j] = math.sqrt((self.positions[i][0] - self.positions[j][0])**2 +
(self.positions[i][1] - self.positions[j][1])**2)
max_distance = max(max(row) for row in distance_matrix)
min_distance = min(min(row) for row in distance_matrix)
return distance_matrix, max_distance, min_distance
def calc_path_distance(self, path):
return self.common_func.calc_path_distance(path)
def construct_solution(self, gen):
# 构建解决方案:双机械臂路径规划
all_paths = []
all_distances = []
# 为每只蚂蚁构建路径
for ant in range(self.num_ants):
path = [[0],[self.x_num*self.y_num*2+1]]
visited_supply = set()
visited_target = set()
# 构建路径直到完成所有任务
start_time=time.time()
memory=[]
while len(path[0])-1< self.empty_num:
if self.empty_num %2!= 0:
if len(path[0]) == self.empty_num:
break
next_points=[]
current = path[0][-1] if len(path[0]) > 1 else path[0][0]
# 奇数步:选择供应苗盘点
if len(path[0]) % 2 == 1:
available_points = [p for p in self.supply_need_number if p not in visited_supply]
if not available_points:
break
# 计算转移概率
probabilities = {}
for next_point in available_points:
pheromone = self.pheromone_matrix[current][next_point] ** self.alpha
visibility = ((self.max_distance - self.distance_matrix[current][next_point])/(self.max_distance - self.min_distance)) ** self.beta
probabilities[next_point] = pheromone * visibility
# 偶数步:选择目标苗盘点
# 偶数步:选择目标苗盘点
else:
available_points = [p for p in self.target_need_number if p not in visited_target]
if not available_points:
break
# 计算转移概率
probabilities = {}
for next_point in available_points:
pheromone_value = max(self.pheromone_matrix[current][next_point], 1e-10)
pheromone = pheromone_value ** self.alpha
visibility = ((self.max_distance - self.distance_matrix[current][next_point])/(self.max_distance - self.min_distance)) ** self.beta
# visibility = (1 / self.distance_matrix[current][next_point]) ** self.beta
probabilities[next_point] = pheromone * visibility
# 归一化概率
total = sum(probabilities.values())
normalized_probs = {k: v/total for k, v in probabilities.items()}
# 基于列概率选择下一个点
col_probabilities = []
probabilities_array=np.zeros((self.x_num,self.y_num))
probabilities_array=np.reshape(probabilities_array,(self.y_num,self.x_num))
log_num=[]
# 计算每列的平均概率
for j in range(self.x_num):
num=0
colomn_sum = 0
for i in range(self.y_num):
if len(path[0]) % 2 == 1:
probabilities_array[i][j] = normalized_probs.get(self.x_num*self.y_num+1+self.x_num*i+j,0)
else:
probabilities_array[i][j] = normalized_probs.get(1+self.x_num*i+j,0)
colomn_sum += probabilities_array[i][j]
if probabilities_array[i][j] != 0:
num+=1
log_num.append(num)
col_probabilities.append(colomn_sum/num if num != 0 else 0)
# 选择列与点
if len(path[0]) % 2 == 1:
order_array = self.supply_order_array.copy()
else:
order_array = self.target_order_array.copy()
next_col = random.choices(list(range(0,self.x_num)),list(col_probabilities), k=1)[0]
normalized_col_probabilities = [prob / sum(probabilities_array[:,next_col]) for prob in probabilities_array[:,next_col]]
# 选择两个点作为下一步
if log_num[next_col] > 1:
next_points = np.random.choice(order_array[:,next_col], size=2, p=normalized_col_probabilities,replace=False)
else:
#直接去找奇数列
next_points.append(np.random.choice(order_array[:,next_col], size=1, p=normalized_col_probabilities,replace=False)[0])
col_probabilities[next_col] = 0
log_num[next_col]-=1
odd_indices = np.where(np.array(log_num) % 2 == 1)[0]
col_probabilities=[col_probabilities[i] for i in odd_indices]
if odd_indices.size == 0:
memory.append(next_points[0])
num=0
visited_target.add(next_points[0])
continue
next_col = random.choices(odd_indices, list(col_probabilities), k=1)[0]
normalized_col_probabilities = [prob / sum(probabilities_array[:, next_col]) for prob in probabilities_array[:, next_col]]
next_points.append(np.random.choice(order_array[:, next_col], size=1, p=normalized_col_probabilities, replace=False)[0])
# 选择下一个点
order_next_point = sorted(next_points)
# 更新路径和已访问集合
for i in range(2):
path[i].append(int(order_next_point[i]))
if len(path[0]) % 2 == 0:
visited_supply.add(int(order_next_point[i]))
del probabilities[int(order_next_point[i])]
else:
visited_target.add(int(order_next_point[i]))
del probabilities[int(order_next_point[i])]
end_time=time.time()-start_time
# print(end_time)
# 处理待移栽苗数为奇数的最后情况
if self.empty_num % 2 != 0:
# memory=0
# 随机选择最后一个点加到哪一个路径中
if random.random() < 0.5:
selected = 0
else:
selected = 1
available_points = [p for p in self.supply_need_number if p not in visited_supply]
# 计算转移概率
# available_points = [p for p in self.supply_need_number if p not in visited_supply]
# if not available_points:
# break
probabilities = {}
for next_point in available_points:
pheromone = self.pheromone_matrix[current][next_point] ** self.alpha
visibility = ((self.max_distance - self.distance_matrix[current][next_point])/(self.max_distance - self.min_distance)) ** self.beta
probabilities[next_point] = pheromone * visibility
total = sum(probabilities.values())
normalized_probs = {k: v/total for k, v in probabilities.items()}
# 基于列概率选择下一个点
col_probabilities = []
probabilities_array=np.zeros((self.x_num,self.y_num))
probabilities_array=np.reshape(probabilities_array,(self.y_num,self.x_num))
log_num=[]
for j in range(self.x_num):
num=0
colomn_sum = 0
for i in range(self.y_num):
if len(path[0]) % 2 == 1:
probabilities_array[i][j] = normalized_probs.get(self.x_num*self.y_num+1+self.x_num*i+j,0)
else:
probabilities_array[i][j] = normalized_probs.get(1+self.x_num*i+j,0)
colomn_sum += probabilities_array[i][j]
if probabilities_array[i][j] != 0:
num+=1
log_num.append(num)
col_probabilities.append(colomn_sum/num if num != 0 else 0)
# 选择列与点
if len(path[0]) % 2 == 1:
order_array = self.supply_order_array.copy()
else:
order_array = self.target_order_array.copy()
next_col = random.choices(list(range(0,self.x_num)),list(col_probabilities), k=1)[0]
normalized_col_probabilities = [prob / sum(probabilities_array[:,next_col]) for prob in probabilities_array[:,next_col]]
path[selected].append(np.random.choice(order_array[:,next_col], size=1, p=normalized_col_probabilities,replace=False)[0])
if len(memory)==0:
available_points = [p for p in self.target_need_number if p not in visited_target]
path[selected].append(available_points[0])
else:
path[selected].append(memory[0])
# 完成路径,返回原点
path[0].append(0)
path[1].append(2*self.x_num*self.y_num+1)
all_paths.append(path)
all_fitness=self.fitness(arr=all_paths,gen=gen)
return all_paths, all_fitness
def update_pheromones(self, all_paths, all_fitnesses, gen):
# 信息素挥发
self.pheromone_matrix *= (1 - self.evaporation_rate)
# 根据路径质量更新信息素
for i, path in enumerate(all_paths): # i表示第i个蚂蚁
fitness = all_fitnesses[i] # 第i个蚂蚁的解决方案适应度
# 遍历该蚂蚁的双机械手路径
for k in range(2): # k表示第k个机械手
for j in range(len(path[k]) - 1):
self.pheromone_matrix[path[k][j]][path[k][j + 1]] += self.Q * fitness/40
tem=[path[k][j],path[k][j + 1]]
for k in range(2):
for j in range(len(self.best_path) - 1):
self.pheromone_matrix[self.best_path[k][j]][self.best_path[k][j + 1]] += self.Q / self.best_fitness
def save_pheromone_matrix_to_excel(self, filename="pheromone_matrix.xlsx"):
"""
将信息素矩阵保存为Excel文件
参数:
filename (str): 保存的Excel文件名
"""
try:
import pandas as pd
# 创建DataFrame
df = pd.DataFrame(self.pheromone_matrix)
# 添加行列标签(可选)
row_labels = [f"点{i}" for i in range(self.num_points)]
col_labels = [f"点{i}" for i in range(self.num_points)]
df.index = row_labels
df.columns = col_labels
# 保存到CSV
df.to_csv(filename)
print(f"信息素矩阵已保存至 {filename}")
except Exception as e:
print(f"保存信息素矩阵时出错: {e}")
def run(self, max_generation=1, max_consecutive_no_improvement=10):
# 执行蚁群算法主循环
time_start = time.time()
gen = 0
consecutive_no_improvement = 0
fitness_history = []
log_time = []
# 迭代直到满足收敛条件
# max_alpha_num=len(self.alpha)
while consecutive_no_improvement < max_consecutive_no_improvement and gen < max_generation:
# 构建解决方案并评估
# if gen<max_alpha_num:
# gen_alpha=self.alpha[gen]
# else:
# gen_alpha=self.alpha[-1]
# time_start = time.time()
# all_paths, all_fitnesses = self.construct_solution(gen, gen_alpha)
all_paths, all_fitnesses = self.construct_solution(gen)
best_index = np.argmax(all_fitnesses)
current_best_fitness = all_fitnesses[best_index]
# 更新全局最优解
if current_best_fitness > self.best_fitness:
self.best_fitness = current_best_fitness
self.best_path = all_paths[best_index]
consecutive_no_improvement = 0
else:
consecutive_no_improvement += 1
# 更新信息素和历史记录
self.update_pheromones(all_paths, all_fitnesses, gen)
fitness_history.append(self.best_fitness)
# gen += 1
# gen_time = time.time() - time_start
# log_time.append(gen_time)
# print(f"第{gen}代: 最佳适应度 = {self.best_fitness:.4f}, 迭代时间 = {gen_time:.2f}秒")
# 输出收敛信息
print(f"\n算法已收敛! 连续{consecutive_no_improvement}代无改善。")
print(f"总迭代次数: {gen}")
time_end = time.time()
print(f"总运行时间: {time_end - time_start:.2f}秒")
return self.best_path, self.best_fitness, fitness_history
def plot_path(self,path=None):
if path is None:
path = self.best_path
# 可视化路径
return self.common_func.plot_path(path)
def calc_time(self, path):
return self.common_func.calc_time(path)
def calc_distance(self, path):
return self.common_func.calc_distance(path)
def fitness(self, arr, gen):
return self.common_func.fitness(arr=arr, gen=gen)
def main():
"""
主函数:设置参数并运行蚁群算法,输出结果并可视化路径
"""
# 程序入口:设置参数并运行算法
start_time = time.time()
# 问题与算法参数设置
x_num = 6
y_num = 12
empty_num = 9
num_ants = 20
alpha = 3
beta = 3
evaporation_rate = 0.5
Q = 1
# 创建并运行蚁群算法
aco = AntColonyOptimization(
x_num=x_num,
y_num=y_num,
empty_num=empty_num,
num_ants=num_ants,
alpha=alpha,
beta=beta,
evaporation_rate=evaporation_rate,
Q=Q,
random_seed=1
)
best_path, best_distance, fitness_history = aco.run(max_generation=100, max_consecutive_no_improvement=30)
# 输出结果
print(f"种群规模:{num_ants}")
print(f"信息素重要性因子:{alpha}")
print(f"启发式因子重要性:{beta}")
print(f"信息素挥发率:{evaporation_rate}")
print(f"缺苗盘数量:{empty_num}")
print(f"最优路径: {best_path}")
print(f"总距离: {best_distance:.2f}")
end_time = time.time()
print(f"运行时间: {end_time - start_time:.2f} 秒")
# 可视化结果
aco.plot_path()
# 绘制收敛曲线
plt.figure(figsize=(10, 8))
plt.plot(range(len(fitness_history)), fitness_history)
plt.title('蚁群算法收敛曲线')
plt.xlabel('代数')
plt.ylabel('最优适应度')
plt.grid(True)
plt.show()
if __name__ == "__main__":
main()
帮我使用numba或cython改写该代码,生成一些必要的文件也行