蚁群优化算法

1.基本原理

蚁群算法模拟了自然界中蚂蚁寻找食物的群体智慧。蚂蚁在行进途中会释放信息素 ,在寻找路径时,蚂蚁倾向于选择信息素浓度更高的路段。由于短路径往返耗时短、单位时间内通过的次数多,其信息素堆积速度 远超长路径,而挥发损失相对较小。这种"正反馈"机制使得信息素强度在最优路径上迅速跃升,最终引导整个群体收敛至全局最优解。

2.代码实现

python 复制代码
# -*- coding:utf-8 -*-

import time
import platform

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


system = platform.system()
if system == "Darwin":  # macOS
    plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
elif system == "Windows":
    plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


class ACOConfig:
    def __init__(self):
        self.ant_num = 60           # 蚂蚁数量
        self.city_num = 50          # 城市数量
        self.max_iter = 200         
        self.alpha = 1.0            # 信息素重要程度
        self.beta = 4.0             # 启发函数重要程度
        self.rho = 0.1              # 挥发系数
        self.Q = 10.0               # 信息素强度基数
        self.p_min = 0.01           # 最小信息素限制
        self.p_max = 5.0            # 最大信息素限制
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

class ACO:
    def __init__(self, config):
        self.config = config
        
        self.city_pos = torch.rand((config.city_num, 2), device=config.device) * 100
        self.dist_mat = torch.cdist(self.city_pos, self.city_pos, p=2)
        
        # 初始化信息素
        self.pheromone_mat = torch.full((config.city_num, config.city_num), config.p_max, device=config.device)
        # 计算启发信息 1/d
        self.heuristic_mat = 1.0 / (self.dist_mat + torch.eye(config.city_num, device=config.device))
        
        self.best_path = None
        self.best_path_length = float('inf')
        self.history = []

    def _select_next_cities(self, current_cities, allowed_mask):
        # 选择得分
        p = self.pheromone_mat[current_cities, :] ** self.config.alpha
        h = self.heuristic_mat[current_cities, :] ** self.config.beta
        score = p * h * allowed_mask
        
        # 轮盘赌采样
        probs = score / (torch.sum(score, dim=1, keepdim=True) + 1e-10)
        return torch.multinomial(probs, 1).squeeze(1)

    def _get_path_lengths(self, paths):
        next_paths = torch.roll(paths, shifts=-1, dims=1)
        # 提取路径距离
        lengths = self.dist_mat[paths, next_paths] 
        return torch.sum(lengths, dim=1)

    def _update_pheromone(self, paths, lengths, iter_best_idx):
        self.pheromone_mat *= (1 - self.config.rho)
        
        delta_p = self.config.Q / lengths
        from_nodes = paths.flatten()
        to_nodes = torch.roll(paths, shifts=-1, dims=1).flatten()
        updates = delta_p.repeat_interleave(self.config.city_num)
        
        self.pheromone_mat.index_put_((from_nodes, to_nodes), updates, accumulate=True)
        self.pheromone_mat.index_put_((to_nodes, from_nodes), updates, accumulate=True)
        
        self.pheromone_mat = torch.clamp(self.pheromone_mat, self.config.p_min, self.config.p_max)
        
        self.pheromone_mat.fill_diagonal_(0)

    def run(self):
        print(f"执行设备: {self.config.device} | 城市规模: {self.config.city_num}")
        start = time.time()
        
        for i in range(self.config.max_iter):
            # 每代初始状态
            paths = torch.zeros((self.config.ant_num, self.config.city_num), dtype=torch.long, device=self.config.device)
            paths[:, 0] = torch.randint(0, self.config.city_num, (self.config.ant_num,), device=self.config.device)
            
            mask = torch.ones((self.config.ant_num, self.config.city_num), device=self.config.device)
            ant_idx = torch.arange(self.config.ant_num, device=self.config.device)
            mask[ant_idx, paths[:, 0]] = 0
            
            # 构建路径
            for step in range(1, self.config.city_num):
                next_c = self._select_next_cities(paths[:, step-1], mask)
                paths[:, step] = next_c
                mask[ant_idx, next_c] = 0
            
            lengths = self._get_path_lengths(paths)
            
            # 找到本代最优
            val, idx = torch.min(lengths, dim=0)
            if val < self.best_path_length:
                self.best_path_length = val.item()
                self.best_path = paths[idx].cpu().clone()
            
            self.history.append(self.best_path_length)
            self._update_pheromone(paths, lengths, idx)
            
            if (i + 1) % 20 == 0:
                print(f"迭代 [{i+1:03d}] 最优长度: {self.best_path_length:.4f}")

        print(f"\n优化完成!耗时: {time.time()-start:.2f}s")

    def plot(self):
        
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
        
        # 绘制路径
        coords = self.city_pos.cpu().numpy()
        p = self.best_path.numpy()
        p = np.append(p, p[0])
        ax1.plot(coords[p, 0], coords[p, 1], 'r-o', markersize=6, linewidth=1)
        ax1.set_title(f"最佳路径图 (长度: {self.best_path_length:.2f})")
        
        # 绘制收敛曲线
        ax2.plot(self.history, color='blue')
        ax2.set_title("收敛曲线")
        ax2.set_xlabel("迭代")
        ax2.set_ylabel("距离")
        
        plt.tight_layout()
        plt.show()

if __name__ == "__main__":
    conf = ACOConfig()
    model = ACO(conf)
    model.run()
    model.plot()

运行效果

bash 复制代码
执行设备: cpu | 城市规模: 50
迭代 [020] 最优长度: 607.0824
迭代 [040] 最优长度: 550.5231
迭代 [060] 最优长度: 549.9612
迭代 [080] 最优长度: 549.9612
迭代 [100] 最优长度: 545.2683
迭代 [120] 最优长度: 545.2683
迭代 [140] 最优长度: 545.2683
迭代 [160] 最优长度: 545.2683
迭代 [180] 最优长度: 545.2683
迭代 [200] 最优长度: 545.2683

优化完成!耗时: 0.99s
相关推荐
Easy_API1 小时前
2.8万亿参数,编程反超GPT-6 Astra:Kimi K3.1 Pro把开源模型推到了哪一步
大数据·人工智能·gpt·深度学习
GlobalInfo1 小时前
2026年机器人多指灵巧手市场分析报告——涵盖行业调查、趋势分析与发展前景
大数据·人工智能·microsoft·微服务·机器人
代码山河2 小时前
Python就业方向全解析:后端、爬虫、数据分析、AI你选哪个?
python·学习·架构·教程·面向对象·项目
紧跟先前的步伐2 小时前
Go AI Agent 实战 24|工具系统工程化收尾与阶段验收
人工智能·ai·golang·1024程序员节
在世修行2 小时前
智学文枢:题目流水线
python·多线程·状态机·pyside
释厄6232 小时前
AI学习层更新与跨体转移律——人类社会同构·不缺理解缺 U
人工智能·学习
梯度下降者2 小时前
零基础入门Python 爬虫
爬虫·python·数据分析·入门指南·webcrawler
老金带你玩AI3 小时前
集万家所长,一键复制的Agent.md!
人工智能
ZhuoAIStage3 小时前
舞台工艺多专业审图提速:用 AI 智能体编排 A+B+C+G 四段读图流水线
人工智能·自动化·工作流编排·舞台工艺·审图智能体
小奶包他干奶奶3 小时前
AI学习——1、机器学习概念
人工智能·机器学习