论文复现丨物流中心选址问题:蜘蛛猴算法求解

news2024/9/23 19:17:42


路径优化系列文章:

  • 1、路径优化历史文章
  • 2、物流中心选址问题论文复现丨改进蜘蛛猴算法求解

物流中心选址问题

一般物流中心选址问题是指:在有限的用户(即需求点)中找出一定数量的地点建立配送中心,实现从物流中心到用户之间的配送,使得各配送中心到由它配送用户的需求量与距离的乘积之和最小。

本文假设:

(1)不考虑物流中心的规模及经济问题;

(2)配送中心必须满足所有位置的需求;

(3)不考虑其他费用。

模型

推文的测试模型包括基准函数和中心选择问题,以下是5个基准函数,可以任意增加:

在文件HS:

基准函数纬度n目前设置为20,可修改。

物流中心选址问题的目标函数和约束见参考文献:

数据

论文数据,31个城市选6个中心的数据(复制pdf数据到txt):

1 (1304,2312) 20 17 (3918,2179) 90 
2 (3639,1315) 90 18 (4061,2370) 70 
3 (4177,2244) 90 19 (3780,2212) 100 
4 (3712,1399) 60 20 (3676,2578) 50 
5 (3757,1187) 70 21 (4029,2838) 50 
6 (3326,1556) 70 22 (4263,2931) 50
7 (3238,1229) 40 23 (3429,1908) 80 
8 (4196,1044) 90 24 (3507,2376) 70 
9 (4312,790) 90 25 (3394,2643) 80 
10 (4386,570) 70 26 (3439,3201) 40 
11 (3007,1970) 60 27 (2935,3240) 40 
12 (2562,1756) 40 28 (3140,3550) 60 
13 (2788,1491) 40 29 (2545,2357) 70 
14 (2381,1676) 40 30 (2778,2826) 50 
15 (1332,695) 20 31 (2370,2975) 30 
16 (3715,1678) 80

按行和空格拆分数据,具体读取在文件read_decode_paint。

编码解码

编码

基准函数和选址问题都需要生成指定纬度下的随机初始解,2-16生成方式:

基准的最大最小值见函数定义域,对于选址问题,设置最大值为1,最小值为0。

选址问题的初始解还需转换编码:

这其中会出现问题,候选中心数大于或小于设定值。文献是选择6个点,当编码1的计数大于或者小于6,是非可行解,需要修正解。

修正方法:大于6个点时,排序编码x的所有基因值,更正最大6个以外的1为0;小于6个点时,排序编码x的所有基因值,更正不足6个外的0为1.。

如3个点选择2个中心

x=[0.6,0.55,0.8],转换编码 y=[1,1,1],修正编码为y= [1,0,1],保留最大2个,0.55对应的1修正为0

x=[0.35,0.4,0.8],转换编码 y=[0,0,1],修正编码为y= [0,1,1],补充次大的1个,0.4对应的0修正为1

核心代码:

def f_xuan(n,num,x):
    if x==[]:                             # 为空时生成初始解
        x = []
        for i in range(n):
            xx = np.random.random()       # 0到1生成初始解
            x.append(xx)
    y = []
    for xx in x:                          # 编码转化为0,1
        if xx < .5:
            y.append(0)
        else:
            y.append(1)
    idx = np.array(x).argsort()           # 排序x
    y1 = np.array(y)
    if sum(y)<num:                        # 如果1的计数小于候选数,补充1
        y1[idx[-num:]] = 1
    else:                                 # 否则删除1
        y1[idx[:-num]] = 0
    return x, y1.tolist()

解码

基准函数解码较为简单,新解传入对应函数就能返回目标。选址问题设计1种贪婪选择策略:对于每个点,计算点到所有候选中心的距离与需求量的乘积,选择乘积最小对应的中心:

代码如下:

def decode(y,inf):
    center_idx = [i for i in range(len(y)) if y[i] == 1]  # 候选位置读取
    center_road = [[] for i in range(len(center_idx))]
    f = 0
    for w in range(len(y)):
        if y[w] == 0:
            disdemand = [np.sqrt((inf[w][0]-inf[c][0])**2 + (inf[w][1]-inf[c][1])**2)*inf[w][2] for c in center_idx]
            f += min(disdemand)                          # 目标更新
            idx = disdemand.index(min(disdemand))        # 最小目标对应的候选中心
            center_road[idx].append(w)                   # 对应候选中心加入点

改进算法

算法步骤

Step 1. 设置参数。种群规模 P ,最大迭代次数 N ,干扰率 pr ,最大组数 MG ,全局 领导限制 gll,局部领导限制lll ,指引因子最大值cmax 及最小值cmin ,变异概率β。

Step 2. 用公式(2-16)生成群体中所有蜘蛛猴的初始位置。然后对每个蜘蛛猴的适应度值 进行计算并排序,选出局部和全局领导者。

Step 3. 当不满足终止条件时,执行以下步骤:

Step 3.1. 为了寻找最优解,利用(3-2)式产生新的位置;结合每只猴子适应性的大小择 优选出适宜的位置。

Step 3.2. 根据(2-19)式,得出全部组中个体被筛选的可能性;然后利用(3-4)式将选中的 蜘蛛猴进行位置更新。

Step 3.3. 对全部组的猴子筛选,选出局部及全局指引者的位置。

Step 3.4. 如果任何一个局部指引者在指定次数(即局部指引限制lll )没有更新其位置,那 么局部指引者会再次带领该组全部猴子寻找食物,根据扰动率 pr 的大小采取式(2-21)来更 新它们的位置。

Step 3.5. 执行 Cauchy 变异操作,根据式(3-5)更新蜘蛛猴的位置,选出较优的位置。

Step 3.6. 如果全局指引者在指定次数(即全局领导限制 gll )没有更新其位置,且此时没有达到最大组数 MG ,最优指引者会将群体进行分组;否则,最优指引者会把全部小组并 为一组。

3-2更新方式:

代码没有加λ,可以自行调整。

3-4更新方式:

3-5更新方式:

核心代码:

for g in range(self.N):
    if g == 0:
        Total_x, answer = self.creat(wd, hs)                      # 2-16生成初始位置            
        best_idx = answer.index(min(answer))
        gbest, pbest = Total_x[best_idx], Total_x[best_idx]       # 初始全局和局部领导者
        pbidx = [best_idx]
        pbcount = [0]
        result[0].append(g)
        result[1].append(min(answer))
    for w in range(self.P):
        r = np.random.randint(0, self.P)                          # 随机选择索引
        xr = Total_x[r]
        x = Total_x[w]
        mu = 1 - g/self.N
        xnew = x + mu*(pbest - x) + mu*(xr - x)                  # 3-2更新方式
        prob = .9*(answer[w]/max(answer)) + .1              
        if np.random.random() < prob:                            # 2-19方法概率计算,
            x = xnew
            f = answer[w]
            fmin = min(answer)
            fave = sum(answer)/len(answer)
            if f<= fave:
                c = self.cmin + (self.cmax-self.cmin)/(fave - fmin)*(f - fmin)  # c值计算方式
            else:
                c = self.cmax
            xnew = x + c*np.random.random()*(gbest - x) + c*np.random.uniform(-1,1)*(xr - x)
                                                            # 3-4计算方式
        if hs == 'f_xuan':
            x, y = rdp.f_xuan(31,6,xnew)
            center_road,center_idx,f = rdp.decode(y,inf)
        else:
            x1, f = eval(f'HS.{hs}({wd},{xnew.tolist()})')
        if f < answer[w]:                                   # 新解优于原解时更新
            Total_x[w] = xnew
            answer[w] = f
    best_idx1 = answer.index(min(answer))
    if best_idx1 == best_idx:                               # 全局最优位置不变时,gl加1
        gl += 1
    else:                                                   # 否则归0
        gl = 0
    lenth = int(self.P/len(pbidx))                          # 目前的组数
    
    for w in range(len(pbidx)):
        pbans = answer[lenth*w:lenth*(w+1)]                 # 截取每个组的目标
        pbid = pbans.index(min(pbans))                      # 每个组的最优解(局部领导)
        if pbid == pbidx[w]:                                # 局部领导位置不变时,该位置计数加1
            pbcount[w] += 1
        else:                                               # 否则归零
            pbcount[w] = 0
        if pbcount[w] == self.lll:                          # 如果达到局部领导限制
            for k in range(lenth):
                if np.random.random() < pr:                 # 一定概率下随机生成初始解
                    xnew, f = eval(f'HS.{hs}({wd},[])')
                else:
                    r = np.random.randint(0, P)                         # 否则随机选择索引
                    xr = Total_x[r]          
                    x = Total_x[w]
                    xnew = x + np.random.random()*(pbest - x) + np.random.random()*(xr - x)  # 2-21更新方式
                    f = HS.f1c(xnew)
                Total_x[lenth*w + k] = xnew
                answer[lenth*w + k] = f
    
    for w in range(self.P):                                 #  Cauchy 变异操作
        x = Total_x[w]
        if np.random.random() < self.β:
            a = 2*(1- g/self.N)
            xnew = x + a*math.tan(np.pi*(np.random.random() - .5))  # 3-5更新方式
        else:
            xnew = x
        if hs == 'f_xuan':
            x, y = rdp.f_xuan(31,6,xnew)
            center_road,center_idx,f = rdp.decode(y,inf)
        else:
            x1, f = eval(f'HS.{hs}({wd},{xnew.tolist()})')
        if f < answer[w]:                                   # 新解优于原解时更新
            Total_x[w] = xnew
            answer[w] = f

    if gl == self.gll:                                   # 如果到达全局领导限制,组数加1            
        mg += 1
    if mg == self.MG:                                    # 如果组数到达限制,归1,全局领导和局部领导相同
        mg = 1
        best_idx = answer.index(min(answer))
        pbidx = [best_idx]
    else:                                               # 没到达组数限制时
        pbidx = []
        lenth = int(self.P/mg)                          # 新的组数(+1)对应的组长度
        pbcount = []
        for mgg in range(mg):               
            pbans = answer[lenth*mgg:lenth*(mgg+1)]     # 组长度对应的目标
            bid = pbans.index(min(pbans))               # 局部领导位置
            pbidx.append(bid)
            pbcount.append(0)                           # 局部领导位置计数

结果

代码运行环境
windows系统,python3.6.0,第三方库及版本号如下:

matplotlib (3.3.4)
numpy (1.19.5)
pandas (1.1.5)
xlrd (1.2.0)
XlsxWriter (3.0.3)

第三方库需要在安装完python之后,额外安装,以前文章有讲述过安装第三方库的解决办法。

主函数

设计主函数如下:

from cmasmo import CMASMO
import paint
import HS
import read_decode_paint as rdp
import numpy as np


P = 50       # 种群规模       
N = 1000     # 迭代次数
pr = .5      # 扰动率
MG = 5       # 最大组数
gll = 50     # 全局领导限制
lll = 1500   # 局部领导限制
cmax = .8    # 最高学习因子
cmin = .3    # 最低学习因子
β = .8       # 变异概率

wd = 20      # 函数纬度,目前是20
hs = 'f1'    # 函数:f1到f5 和 f_xuan

if hs == 'f_xuan':  # 选址问题视数据而定,目前是31
    wd = 31

cm = CMASMO(P, N, pr, MG, gll, lll, cmax, cmin, β)
x,result = cm.total(wd, hs)

print('*'*20)
if hs == 'f_xuan':
    inf = rdp.get()
    x, y = rdp.f_xuan(31,6,x)              # 目前是31点选择6个中心,修正时cmasmo对应行也修正
    center_road,center_idx,f = rdp.decode(y,inf)
    print('选择中心编码:',y)
    print('对应点:',np.array(center_idx)+1)
    print('目标:',f)
    
    rdp.draw(center_road,center_idx,f,inf)
else:
    x1, f = eval(f'HS.{hs}({wd},{x})')
    print('函数解:',x)
    print('目标:',f)
rdp.draw_change(result)

运行结果

f1结果如下:

f1目标随迭代次数的变化图如下:

f2目标随迭代次数的变化图如下:

f3目标随迭代次数的变化图如下:

f4目标随迭代次数的变化图如下:

f5目标随迭代次数的变化图如下:

f_xuan结果如下:

选址图

f_xuan目标随迭代次数的变化图如下:

结论

  • 本推文主要是对参考论文进行复现,为了解可行设计了选址中心的编码修正方式,为了求解效率设计了贪婪的中心选择方式。其中基准函数容易陷入局部最优,可从算法参数、算法流程、初始解或者函数定义域等进行优化,基准函数目前是5个,其余的可自行在HS添加。

  • 数据和算法皆可修改(修改选址数据时,其一行包含1个或者2个点的相关数据,否则报错,中心点和选择个数在main和cmasmo都需修改)。

  • 参考文献:蜘蛛猴算法的改进及其在物流中心选址问题中的应用_杨转(第3章)

代码

为了方便和便于修改和测试,把代码在4个py文件里。

演示视频:

论文复现丨物流中心选址问题:蜘蛛猴算法求解

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

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

相关文章

实验3.mbr读取硬盘

简介 实验&#xff1a;编写 mbr&#xff0c;读取0盘0道2扇区的内容写入内存&#xff0c;然后跳转执行写好的loader.s 代码 boot/mbr.s ; boot/mbr.s ; 功能&#xff1a;读取磁盘&#xff0c;加载loader到内存并跳转到loader%include "boot.inc" SECTION MBR vsta…

【Python 基础】方法

方法 方法和函数是一回事,只是它是调用在一个值上。例如,如果一个列表值存储在 spam 中,你可以在这个列表上调用 index()列表方法(稍后我会解释),就像spam.index(‘hello’)一样。方法部分跟在这个值后面,以一个句点分隔。 每种数据类型都有它自己的一组方法。例如,列…

Qt5.12.2安装教程

文章目录 文章介绍下载连接安装教程 文章介绍 安装Qt5.12.2 下载连接 点击官网下载 安装包下载完毕 安装教程 点开设置&#xff0c;添加临时储存库&#xff0c;复制连接“https://download.qt.io/online/qtsdkrepository/windows_x86/root/qt/” 点击测试&#xff0…

航空航天用电机控制器和车规级电机控制器有什么区别?

航空航天用电机控制器和车规级电机控制器有什么区别&#xff1f; 1.标准与认证要求2.工作环境与温度范围3.可靠性与容错性4.性能要求5.使用寿命与维护6.成本与批量生产 最近遇到这样一个问题&#xff0c;处在航空航天动力系统行业中&#xff0c;也会经常遇到类似的问题&#xf…

Spring框架(三)——AOP--基础部分

1、概括 将与核心业务无关的代码独立的抽取出来&#xff0c;形成一个独立的组件&#xff08;抽取公共代码的过程&#xff09;&#xff0c;然后以横向交叉的方式应用到业务流程当中的过程被称为AOP优点 代码复用性强 代码易维护 使开发者更专注于业务逻辑 2、AOP的底层原理&…

探索APP开发中的主流版式设计与应用实践

在当今移动互联网高速发展的时代&#xff0c;APP已成为人们日常生活中不可或缺的一部分。无论是社交娱乐、购物支付还是工作学习&#xff0c;各类APP都以其独特的界面设计和用户体验赢得了用户的青睐。而APP开发的版式设计和页面规范&#xff0c;则是决定用户体验好坏的关键因素…

打卡第15天------二叉树

最近公司给我派活儿太多了,要干好多活儿,好多工作任务要处理,我都没时间刷题了。leetcode上的题目通过数量一直停留在原地不动,我真的很着急呀,我现在每天过的都有一种紧迫感,很着急,有一种与时间赛跑的感觉,真的时间过的太快了,没有任何人能够阻挡住时间的年轮向前推…

SongComposer:让大模型像人类一样具有音乐创作力

人工智能咨询培训老师叶梓 转载标明出处 大模型在翻译、复杂语言环境中的推理等任务中展现出了人类级别的能力。这引发了一个问题&#xff1a;这些模型能否在更具情感、抽象性以及需要专业技能的领域中&#xff0c;如音乐创作&#xff0c;展现出人类的创造力呢&#xff1f;香港…

IAR启动流程深度“起底”

目录 1. IAR启动流程概述 2.可以不用__iar_program_start吗 3.小结 大家好&#xff0c;今天的肌肉也不是很快乐。 今天聊聊IAR特有的一些启动流程以及在调试的时候遇到的一些问题。 1. IAR启动流程概述 ARM M内核芯片里的启动代码通常会提供Arm、gcc、iar等编译器的模板&…

OrangePi 学习摘录

文章目录 1. 参考2. 开发板 Orange-Pi-CM4 预览3. 烧录 Linux 镜像到 TF 卡中4. 制作桌面版镜像qemu/chroot 5. Armbian6. 编译 1. 参考 淘宝 香橙派官网 Orange-Pi-3B Orange-Pi-CM4 基于docker构建香橙派zero系统构建环境 2. 开发板 Orange-Pi-CM4 预览 3. 烧录 Linux 镜像…

[iOS]浅析isa指针

[iOS]浅析isa指针 文章目录 [iOS]浅析isa指针isa指针isa的结构isa的初始化注意事项 上一篇留的悬念不止分类的实现 还有isa指针到底是什么 它是怎么工作的 class方法又是怎么运作的 class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags 这里面的class又是何方…

【C++11】(lambda)

C11中的lambda与线程。 目录 Lambda&#xff1a;仿函数的缺点&#xff1a;Lambda语法&#xff1a;Lambda使用示例&#xff1a;两数相加&#xff1a;两数交换&#xff1a;解决Goods排序问题&#xff1a; Lambda原理&#xff1a; Lambda&#xff1a; 假设我们有一个商品类&…

controller-from表单1

mvc模式是spring boot 开发web应用程序主要使用模式&#xff0c;mvc分别代表model模型&#xff0c;view是视图 &#xff0c;controller是控制器 controller是对接用户请求数据调用服务层代码&#xff0c;具体怎么操作 浏览器发送http请求给到dispatcherServlet&#xff08;前…

echarts 实现水利计算模型-雨量,流量,时间分割线

需求背景解决效果ISQQW代码地址index.vue 需求背景 实现水利计算模型-雨量&#xff0c;流量&#xff0c;时间分割线 解决效果 ISQQW代码地址 链接 index.vue <!--/** * author: liuk * date: 2024/06/13 * describe: 水利计算模型图表 */--> <template><di…

快速创建一个AI应用

千帆官网&#xff1a;https://console.bce.baidu.com/qianfan/overview 完成的demo&#xff1a;https://dog-tired.github.io/spage_ai/ 这篇博客主要讲述使用千帆免费的大模型接口简单的html页面创建一个AI问答机器人 平台能力 选择使用千帆的speed系列模型&#xff0c;免费…

SpringBoot整合MybatisPlus(详细版)

MybatisPlus简介 1. MybatisPlus 2. 特点 SpringBoot整合MybatisPlus 1. 新建SpringBoot工程 2. 数据准备 3. 引入依赖 4. 配置文件 5. 用MyBatisX-Generator生成代码 整体结构 User类 UserMapper UserServiceImpl UserController类 测试 查询用户表中全部信息 …

Flutter 状态管理新境界:多Provider并行驱动UI

前言 在上一篇文章中&#xff0c;我们讨论了如何使用 Provider 在 Flutter 中进行状态管理。 本篇文章我们来讨论如何使用多个 Provider。 在 Flutter 中&#xff0c;使用 Provider 管理多个不同的状态时&#xff0c;你可以为每个状态创建一个单独的 ChangeNotifierProvider…

C++初学者指南-5.标准库(第一部分)--容器遍历

C初学者指南-5.标准库(第一部分)–容器遍历 文章目录 C初学者指南-5.标准库(第一部分)--容器遍历前向遍历基于范围的循环for_each / for_each_n迭代器的显式使用基于索引的循环 逆向遍历反向范围循环(C20)反向 for_each / for_each_n反向迭代器的显式使用基于索引的反向循环…

2024年TOGAF考试预约流程(纯净版本)

TOGAF考试如何报名&#xff1f;TOGAF考试报名流程是什么&#xff1f;很多文章虽然都有指出来&#xff0c;但是并不明确指出具体流程 今天我们跟着艾威小编一起来看一下这篇纯净版2024年TOGAF考试预约流程&#xff0c;今天我们直说考试报名流程。 01登录官方网址 如果没账号就…

TCP传输控制协议二

TCP 是 TCP/IP 模型中的传输层一个最核心的协议&#xff0c;不仅如此&#xff0c;在整个 4 层模型中&#xff0c;它都是核心的协议&#xff0c;要不然模型怎么会叫做 TCP/IP 模型呢。 它向下使用网络层的 IP 协议&#xff0c;向上为 FTP、SMTP、POP3、SSH、Telnet、HTTP 等应用…