蚁群优化算法

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
相关推荐
SmartBrain2 小时前
FastAPI实战(第三部分):浏览历史的接口开发详解
数据库·人工智能·aigc·fastapi
小锋java12342 小时前
分享一套【优质Python源码】基于Python的Django学生就业管理系统
python
skywalk81632 小时前
解决opencode报错:Error: Failed to spawn OpenCode Server
人工智能
一个处女座的程序猿O(∩_∩)O2 小时前
Python字典详解
开发语言·python
List<String> error_P2 小时前
蓝桥杯基础知识点:模拟-数位操作类题目
python·算法·蓝桥杯
夕除2 小时前
js--22
前端·javascript·python
极客先躯2 小时前
高级java每日一道面试题-2025年7月15日-基础篇[LangChain4j]-如何集成国产大模型(如通义千问、文心一言、智谱 AI)?
java·人工智能·langchain·文心一言·异常处理·密钥管理·参数调优
阿星AI工作室3 小时前
我搭了一个 AI 写作机器人,每天自动写文章发到公众号草稿箱
人工智能·程序员
陈天伟教授3 小时前
人工智能应用- 材料微观:04.微观结构:金属疲劳
人工智能·神经网络·算法·机器学习·推荐算法