蚁群优化算法

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
相关推荐
你的小眼睛ii19 小时前
window本地安装OpenClaw-CN遇到的问题
人工智能
一条咸鱼_SaltyFish19 小时前
从 Spec Coding 到规范驱动 —— AI 编程的确定性边界
人工智能·ai编程·开发者·规范·mcp·speccoding
湘美书院--湘美谈教育19 小时前
湘美书院主理人:AI时代的文雅智能,赏花赏月赏秋香
人工智能·深度学习·神经网络·机器学习·ai写作
aiAIman19 小时前
OpenClaw Web Search 完全指南(2026年3月最新)
人工智能·开源·aigc
清水白石00819 小时前
Python 内存陷阱深度解析——浅拷贝、深拷贝与对象复制的正确姿势
开发语言·python
岛雨QA19 小时前
【基础知识】人工智能大模型常见术语(1)
人工智能·aigc·openai
国家二级编程爱好者19 小时前
删除typora文档没有引用的资源文件
git·python
进击的雷神19 小时前
邮箱编码解码、国际电话验证、主办方过滤、多页面深度爬取——柬埔寨塑料展爬虫四大技术难关攻克纪实
爬虫·python
互联网志20 小时前
为数字经济与人工智能深度融合筑牢坚实底座
人工智能
l1122060320 小时前
网站SEO定时自动发布工具优质厂家推荐
人工智能·推荐·seo优化·网站seo·定时发布工具·优质厂家