python 实现蚁群算法(simpy带绘图)

news2024/9/29 9:26:02

这里使用了蚁群算法求解了旅行商问题,同时结合了simpy来绘图

选择下一个食物的函数为:

probability[i] = pheromone[self.now][self.not_to_foods[i]] ** pheromone_w + (
        1 / distance[self.now][self.not_to_foods[i]]) ** distance_w

该条路概率权重=该点信息素^信息素权重*(1/路径长)^路径权重/总和,这里后面会用random.choices就不用除了

信息素更新为:

new_pheromone[self.route[i]][self.route[i + 1]] += pheromone_Q / self.sum_len
pheromone = np.add((1 - volatilize) * pheromone, new_pheromone)

总信息素会挥发volatilize比例,然后所有蚂蚁路径每一段加上固定释放的信息量/路径总长度

话不多说,都在代码注释里了

import random
import simpy
import matplotlib.pyplot as plt
import numpy as np


# 在这里我们尝试用蚁群算法求解旅行商问题,简而言之,就是寻找一条链接所有点的最短路径最后要回到初始点
# 我想绘制一下每只蚂蚁的行走过程,所以使用上次的simpy包来模拟一下,
# 这个simpy包主要是为了更好的可视化模拟训练过程,你也可以给每只蚂蚁单独线程代替,
# 或者干脆不用管过程,只用一轮一轮的上蚂蚁,在信息素部分做点处理,光看结果也可以。总之大多要比simpy快

class Ant(object):  # 蚂蚁类
    # 说一下训练过程,有很多只蚂蚁,从随机位置出发,
    # 每次遵从信息素的指引,选择下一个城市,直到没有可选城市,回到初始位置然后根据路径总长度在路径上散播信息素
    def __init__(self):  # 蚂蚁构造函数
        # 一只蚂蚁,只需要保存走过的食物就可以,
        # 这里我们为了以后整信息素时不用遍历,顺便保存一下走过的长度
        self.route = []  # 到达食物路径,一个例子是:[2,1,3,2]
        self.not_to_foods = []  # 未到达的食物点
        self.sum_len = 0  # 走过路径总长度
        self.now = 0  # 当前所在位置
        self.next_food = 0  # 下一个所在位置
        self.Initial_Position(random.randint(0,foods_n-1))  # 设定初始位置
        # 绘图参数
        self.now_position = [0, 0]  # 起始到终点的向量
        self.proportion = env.now  # 走的时间,画图就是找到起始食物点,然后加上(起始和终点的向量乘以(当前时间-出发时间)/路长)就是蚂蚁位置,

    def Initial_Position(self, n):  # 选择初始位置'
        self.now = n  # 当前所在的食物
        self.next_food = n  # 下一个要到的食物
        self.route = []
        self.not_to_foods = [i for i in range(foods_n)]  # 未到达的食物点
        self.sum_len = 0
        self.route.append(n)  # 添加到路径
        self.not_to_foods.remove(n)  # 初始点不会在未到的食物点

    def Set_Now(self, next_food):  # 到下一个点
        self.next_food = next_food  # 下一个要到的食物
        self.route.append(next_food)  # 添加到路径
        self.sum_len += distance[self.now][next_food]  # 总路径增加
        if next_food in self.not_to_foods:
            self.not_to_foods.remove(next_food)  # 移出未到的食物点
        self.now_position = foods[next_food] - foods[self.now]  # 走的方向
        self.proportion = env.now  # 出发时间

    def Next_Food(self):  # 根据信息素和路径寻找下一个食物
        len_not_to_foods = len(self.not_to_foods)  # 没选择的食物个数
        probability = np.zeros(len_not_to_foods)  # 选择食物的概率
        for i in range(len_not_to_foods):
            # 选一个路径的概率是该点信息素^信息素权重*(1/路径长)^路径权重/总和,这里后面会用random.choices就不用除了
            probability[i] = pheromone[self.now][self.not_to_foods[i]] ** pheromone_w + (
                    1 / distance[self.now][self.not_to_foods[i]]) ** distance_w
        next_food = random.choices(self.not_to_foods, probability)  # 根据权重选择下一个点
        return next_food

    def Change_Pheromone(self):  # 更新信息素矩阵,先添加到一个临时变量中,信息素矩每隔一段时间后自己会挥发并将这个变量添加进去。
        for i in range(foods_n):
            new_pheromone[self.route[i]][self.route[i + 1]] += pheromone_Q / self.sum_len
            new_pheromone[self.route[i + 1]][self.route[i]] = new_pheromone[self.route[i]][self.route[i + 1]]

    def run(self):  # 蚂蚁出动
        global min_distance, min_route
        while True:
            while self.not_to_foods:  # 未空还能找食物
                next_food = self.Next_Food()[0]
                self.Set_Now(next_food)  # 根据信息素和路径去下一个食物位置
                yield env.timeout(distance[self.now][next_food])  # 等待到达终点
                self.now = next_food  # 到达位置
            # 没有食物可以去了
            next_food = self.route[0]
            self.Set_Now(next_food)  # 去初始点
            yield env.timeout(distance[self.now][next_food])  # 等待到达终点
            self.now = next_food  # 到达位置
            self.Change_Pheromone()  # 到了初始点之后,更新信息素
            if min_distance > self.sum_len:
                min_distance = self.sum_len
                min_route = self.route
            self.Initial_Position(random.randint(0,foods_n-1))  # 重新初始化,再来一轮


def Change_Pheromone(env):
    global pheromone, new_pheromone
    while True:
        # 每隔一段时间,挥发,更新信息素,
        # 我想要平均走完一波蚂蚁更新一波,那么,我大概需要等待平均总路长的时间(因为假设蚂蚁1m/s)这里就用(foods_n+1)/2,两点间平均距离大概是0.5
        yield env.timeout((foods_n + 1) / 2)
        pheromone = np.add((1 - volatilize) * pheromone, new_pheromone)
        new_pheromone = np.zeros((foods_n, foods_n))


# 初始化函数,初始化蚁群,食物,信息素矩阵,
def Initialization(ants_n, foods_n, dimension):
    '''
    :param ants_n:  蚁群大小
    :param foods_n: 食物数目
    :param dimension: 维度
    :return: 初始化蚁群,食物,信息素矩阵,距离矩阵
    '''
    ants = [Ant() for _ in range(ants_n)]  # 蚁群
    np.random.seed(0)  # 随机数种子,让生成的位置一致,你可以删去
    foods = np.random.rand(foods_n, dimension)  # 所有食物位置,支持高维,不过绘图只有二维(python三维图太卡了),只测试二维
    pheromone = np.zeros((foods_n, foods_n))+2  # 信息素矩阵初始为路径长度平均数的倒数之类的
    distance = np.zeros((foods_n, foods_n))  # 距离矩阵
    for i in range(foods_n):  # 计算欧氏距离
        for j in range(foods_n):
            if i > j:  # 以前算过了,抄过来
                distance[i][j] = distance[j][i]
                continue
            if i == j:  # 一样的位置就是0,不算了
                continue
            distance[i][j] = np.sqrt(np.sum((foods[i] - foods[j]) ** 2))
    return ants, foods, pheromone, distance


def plt_Refresh():  # 绘图
    while True:
        plt.clf()  # 清屏
        plt.xlim(0, 1)
        plt.ylim(-0.1, 1)
        # 绘图
        plt.text(0.05, -0.05, "now_time = " + str(env.now))
        for i in range(foods_n):  # 所有的食物点
            for j in range(i):
                plt.plot([foods[i][0],foods[j][0]],[foods[i][1],foods[j][1]],linewidth=pheromone[i][j]/100)
            plt.scatter(foods[i][0], foods[i][1], 100)
            plt.text(foods[i][0], foods[i][1], i)
        for i in range(ants_n):  # 所有的蚂蚁点
            # 到起始食物点,然后加上(起始和终点的向量乘以(当前时间-出发时间)/路长)就是蚂蚁位置,
            if ants[i].now == ants[i].next_food:
                position = foods[ants[i].now]
            else:
                position = foods[ants[i].now] + ants[i].now_position * (env.now - ants[i].proportion) / \
                           distance[ants[i].now][ants[i].next_food]
            plt.scatter(position[0], position[1])
            plt.text(position[0], position[1], i)

        # 刷新图形
        plt.draw()
        plt.pause(time_particles)
        yield env.timeout(time_particles)


def Firing(env):  # env启动
    env.process(Change_Pheromone(env))  # 启动信息素矩阵
    env.process(plt_Refresh())  # 启动绘图
    for i in range(ants_n):  # 启动所有蚂蚁
        env.process(ants[i].run())


ants_n = 15  # 蚂蚁数目,一般1.5*foods_n
foods_n = 10  # 食物数目
dimension = 2  # 维度,建议2,因为绘图只搞了2
min_distance = float("inf")  # 最小距离
min_route = []  # 最小路径
# 一些超参数
pheromone_w = 1  # 信息素权重
distance_w = 6  # 距离权重
volatilize = 0.5  # 信息素挥发比例
pheromone_Q = 10  # 总信息素
run_time = 100  # 模拟时间
time_particles = 0.05  # 绘图间隔
new_pheromone = np.zeros((foods_n, foods_n))
# 绘图
plt.figure()
plt.pause(10)    # 方便我录屏,等10s再出画面你们要删去
env = simpy.Environment()  # 设置环境并启动模拟
ants, foods, pheromone, distance = Initialization(ants_n, foods_n, dimension)  # 初始化,通常,蚁群数目是食物数目1.5倍
print(foods)
Firing(env)  # 开火,启动(添加要模拟的函数)
env.run(until=run_time)  # 运行模拟

print(min_route,min_distance)
plt.show()  # 遍历完成后不消失

自己用建议删去 plt.pause(10)这一行,同时,可以调大time_particles,

这是结果:

视频审核还没通过,通过了就放出来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1235469.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.1 Windows驱动开发:内核监控进程与线程回调

在前面的文章中LyShark一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以监控进程线程创建为例,在Win10系统中监控进程与线程可以使用微软提供给我们的两个新函数来实现,此类函数的原…

完全二叉树你需要了解一下

完全二叉树介绍完全二叉树应用场景完全二叉树和满二叉树的区别完全二叉树代码示例拓展 完全二叉树介绍 完全二叉树(Complete Binary Tree)是一种特殊的二叉树,它的定义是:如果设二叉树的深度为h,除第h层外&#xff0c…

股票扩展功能(十)

A-扩展功能 文章目录 A-扩展功能一. 展示最近10天的斋戒信息, 以 PDF进行预览二. 展示最近10天的斋戒信息, 以 data list 进行响应 一. 展示最近10天的斋戒信息, 以 PDF进行预览 接口描述: 接口地址:/StockApi/extFasting/show 请求方式:GET consumes: produce…

UI for Apache Kafka

文章Overview of UI Tools for Monitoring and Management of Apache Kafka Clusters | by German Osin | Towards Data Science中介绍了8种常见的kafka UI工具,这些产品的核心功能对比信息如下图所示, 通过对比发现 UI for Apache Kafka 功能齐全且免费,因此可以作为我们的首…

gitlab图形化界面使用

gitlab使用 创建用户 上面是创建用户基本操作 修改密码 创建组 给组添加用户 创建项目 选择空白项目 退出root用户,切换其他用户 在服务器上创建ssh密钥 使用ssh-ketgen 命令 新服务器上创建的 [rootgitlab ~]# ssh-keygen Generating public/private rsa key …

uview-plus u-picker的defaultIndexs修改后无效的问题

uniapp项目中使用了uview-plus组件库,在使用u-picker组件时,发现其默认的选中属性 defaultIndex是一次性的,修改后无法响应,解决办法就是在u-picker源码中修改这个属性的watch,源码位置在uni_modules/uview-plus/components/u-pi…

过了那么多1024节才知道……

各位大佬好啊,相信程序员们都知道1024节,那么咱程序员一般会采取什么样的方式来度过程序员节呢?那我们就继续往下看哦,小编包您满意! 先来了解一下历史吧!1024节的起源可以追溯到2009年,当时俄…

【FLink】水位线(Watermark)

目录 1、关于时间语义 1.1事件时间 1.2处理时间​编辑 2、什么是水位线 2.1 顺序流和乱序流 2.2乱序数据的处理 2.3 水位线的特性 3 、水位线的生成 3.1 生成水位线的总体原则 3.2 水位线生成策略 3.3 Flink内置水位线 3.3.1 有序流中内置水位线设置 3.4.2 断点式…

A____Z____RECOVER____DATA勒索恢复---惜分飞

有客户MySQL数据库被黑,业务库中表被删除,并创建A____Z____RECOVER____DATA库,里面有一张readme表,内容为: mysql> select * from readme \G; *************************** 1. row *************************** zh_content: 请尽快与我们取得联系,否则我们将会公…

C#期末速成推荐看的知识和免费视频

【拯救者】C#期末速成 (基础讲解整套题讲解文档下载) 4K ​ 这里讲的是【 🌷速成🌷 速成🌷 速成】版本,按课本章节来, 抽取重点,翻译为人话!!!💝 文末附上 免…

UE5和UE4版本更新重大改变汇总。

转载:UE5和UE4版本更新重大改变汇总。 - 知乎 (zhihu.com) 用户界面变化: 1,原先拖动给放置Actor的place actors,世界大纲,Level等都可以通过右击隐藏到侧边栏; 2,Command命令窗口和ContentBr…

设计模式-命令模式-笔记

“行为变化”模式 在组件的构建过程中,组件行为的变化经常导致组件本身剧烈的变化。“行为变化”模式组件的行为和组件本身进行解耦,从而支持组件行为的变化,实现两者之间的松耦合。 经典模式:Command、Visitor 动机&#xff0…

【LeetCode刷题-链表】--23.合并K个升序链表

23.合并K个升序链表 方法:顺序合并 在前面已经知道合并两个升序链表的前提下,用一个变量ans来维护以及合并的链表,第i次循环把第i个链表和ans合并,答案保存到ans中 /*** Definition for singly-linked list.* public class List…

算法学习 day27

第二十七天 美化数组的最少删除数 2216. 美化数组的最少删除数 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int minDeletion(vector<int>& nums) {int len nums.size();if(len 0) return 0;int res 0,cur 0;for(int i 1;i < len;i)…

spring boot项目未将resource目录标志为资源目录导致配置文件无效因而运行报错问题

能编译&#xff0c;但不能运行。感觉配置文件没有生效。 将程序代码发给同事&#xff0c;我自己能跑&#xff0c;他不能跑&#xff0c;提示无法构造redis对象。redis的链接写在配置文件里&#xff0c;其实是可以连接的。然后从GIT库下载代码&#xff0c;也同样不能跑。同事的操…

OpenCV快速入门:目标检测——轮廓检测、轮廓的距、点集拟合和二维码检测

文章目录 前言一、轮廓检测1.1 图像轮廓的概念1.2 轮廓检测算法简介1.3 轮廓检测基本步骤1.4 轮廓检测函数说明1.4.1 轮廓发现1.4.2 轮廓面积1.4.3 轮廓周长1.4.4 轮廓外接多边形1.4.5 点到轮廓距离1.4.6 凸包检测 1.5 轮廓检测代码实现 二、轮廓的距2.1 几何距2.2 中心距2.3 H…

springcloud医院挂号预约系统源码

开发技术&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;nodejs&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui 功能介绍&#xff1a; 用户端&#xff1a; 登录注册 首页显示医生列表&#xff0c;医院简介&#xff0c;点击医生…

P1141 01迷宫(dfs+染色联通块)

染色联通块&#xff1a; 一个格联通的所有格 每个对应的最大可联通格子的个数均相同 分析&#xff1a; 1.只需要计算每个块里的元素个数 2.元素标记对应某个块 3.查找元素时&#xff1a; 由 &#xff08;1&#xff09;元素坐标-> &#xff08;2&#xff09;查找…

Qt程序的自定义安装卸载方案

前言 NSIS 是一个 Open Source 的 Windows 系统下安装程序制作程序&#xff1b; NSIS-UI-Plugin 是一个开源的NSIS UI插件&#xff1b; 0x0 环境搭建 https://www.cnblogs.com/NSIS/p/16581122.html https://github.com/sway913/NSIS-UI-Plugin 0x1 类图 0x2 二次开发 自定…

图形编辑器开发:自定义光标管理

大家好&#xff0c;我是前端西瓜哥。 今天来讲讲如何在图形编辑器中使用自定义光标&#xff0c;并对光标其进行管理。 编辑器 github 地址&#xff1a; https://github.com/F-star/suika 线上体验&#xff1a; https://blog.fstars.wang/app/suika/ 自定义光标的意义是什么&am…