├── .gitignore ├── LICENSE ├── README.md ├── 哈里斯鹰优化算法 └── 哈里斯鹰优化算法(HHO) │ ├── code │ └── matlab │ │ └── HHO.m │ ├── images │ ├── HHO-1.jpg │ └── HHO-2.jpg │ └── 哈里斯鹰优化算法.md ├── 狼群算法 ├── 灰狼优化算法 │ ├── code │ │ └── matlab │ │ │ └── GWO.m │ ├── images │ │ ├── GWO-1.jpg │ │ └── GWO-2.jpg │ └── 灰狼优化算法.md └── 狼群算法 │ ├── code │ └── matlab │ │ └── WPA.m │ ├── images │ ├── WPA-1.jpg │ └── WPA-2.jpg │ └── 狼群算法.md ├── 粒子群优化算法 ├── 一种新的基于Sigmoid函数的自适应加权粒子群优化器 │ ├── code │ │ └── python │ │ │ └── AWPSO.py │ ├── images │ │ └── AWPSO-1.png │ └── 一种基于Sigmoid函数的自适应加权粒子群优化器.md ├── 一种新的异构改进动态多群粒子群算法 │ └── 一种新的异构改进动态多群粒子群算法.md ├── 双中心粒子群优化 │ ├── code │ │ ├── matlab │ │ │ └── FunDCPSO.m │ │ └── python │ │ │ └── DCPSO.py │ ├── images │ │ └── DCPSO-1.jpg │ └── 双中心粒子群优化.md ├── 完全受扰粒子群优化 │ ├── code │ │ ├── matlab │ │ │ └── TDPSO.m │ │ └── python │ │ │ └── TDPSO.py │ ├── images │ │ ├── TDPSO-1.png │ │ ├── TDPSO-2.png │ │ └── TDPSO-3.png │ └── 完全受扰的混沌粒子群优化算法.md ├── 带收缩因子的粒子群优化 │ ├── code │ │ ├── matlab │ │ │ └── FunVPSO.m │ │ └── python │ │ │ └── VPSO.py │ └── 一种使用收缩因子的粒子群优化算法.md ├── 经典粒子群优化 │ ├── code │ │ ├── matlab │ │ │ ├── FunPSO_GBEST.m │ │ │ ├── FunPSO_LBEST_Logic.m │ │ │ └── FunPSO_Omega.m │ │ └── python │ │ │ ├── OPSO.py │ │ │ ├── PSO_GBEST.py │ │ │ ├── PSO_LBEST_distance.py │ │ │ └── PSO_LBEST_logic.py │ ├── images │ │ ├── PSO流程图.png │ │ └── 粒子速度与位置在二维空间更新.png │ ├── 粒子群优化一.md │ └── 粒子群优化二.md ├── 综合学习粒子群优化 │ ├── code │ │ ├── matlab │ │ │ ├── FunCLPSO_Version1.m │ │ │ ├── FunCLPSO_Version2.m │ │ │ └── FunCLPSO_Version3.m │ │ └── python │ │ │ ├── CLPSO_Version1.py │ │ │ └── CLPSO_Version2.py │ ├── images │ │ ├── CLPSO-1.jpg │ │ ├── CLPSO-2.jpg │ │ ├── CLPSO-3.jpg │ │ └── CLPSO-4.jpg │ └── 综合学习粒子群优化算法.md └── 自适应粒子群优化 │ ├── code │ ├── matlab │ │ └── FunAPSO.m │ └── python │ │ └── APSO.py │ ├── images │ ├── APSO-1.png │ ├── APSO-2.png │ ├── APSO-3.png │ ├── APSO-4.png │ ├── APSO-5.png │ ├── APSO-6.png │ ├── APSO-7.png │ ├── APSO-8.png │ └── APSO-9.png │ └── 自适应粒子群优化算法.md ├── 萤火虫算法 └── 萤火虫优化FA │ ├── code │ ├── matlab │ │ └── FA.m │ └── python │ │ └── FA.py │ ├── images │ └── FA-1.png │ └── 萤火虫算法.md ├── 蚁群优化算法 ├── 一种改进的自适应蚁群算法 │ ├── images │ │ └── IAACO-1.jpg │ └── 一种改进的自适应蚁群算法.md ├── 最大最小蚂蚁系统 │ ├── code │ │ └── matlab │ │ │ ├── Asymmetry_MMAS.m │ │ │ ├── DrawPath.m │ │ │ └── Symmetry_MMAS.m │ └── 最大最小蚂蚁系统.md ├── 蚁群系统 │ ├── code │ │ └── matlab │ │ │ ├── Asymmetry_ACS.m │ │ │ ├── DrawPath.m │ │ │ └── Symmetry_ACS.m │ ├── images │ │ └── ACS-1.jpg │ └── 蚁群系统.md └── 蚂蚁系统 │ ├── code │ └── matlab │ │ ├── Asymmetry_AS.m │ │ ├── DrawPath.m │ │ └── Symmetry_AS.m │ ├── images │ ├── AS-1.jpg │ ├── AS-2.jpg │ └── AS-3.jpg │ └── 蚂蚁系统.md ├── 遗传算法 ├── 多目标遗传算法-(NSGA-Ⅱ) │ ├── images │ │ ├── NSGA-Ⅱ-1.png │ │ ├── NSGA-Ⅱ-2.png │ │ ├── NSGA-Ⅱ-3.png │ │ ├── NSGA-Ⅱ-4.png │ │ └── NSGA-Ⅱ-5.png │ └── 精英非支配排序遗传算法-(NSGAⅡ).md └── 经典遗传算法-GA │ ├── code │ └── python │ │ └── GA_CodingWithFloat.py │ ├── images │ ├── GA-1.png │ ├── GA-2.png │ ├── GA-3.png │ └── GA-4.png │ └── 经典遗传算法-GA.md └── 麻雀搜索算法 └── 麻雀搜索算法SSA ├── code ├── matlab │ └── SSA.m └── python │ └── SSA.py ├── images └── SSA-1.png └── 麻雀搜索算法.md /.gitignore: -------------------------------------------------------------------------------- 1 | ##ignore this file## 2 | /target/ 3 | .vscode 4 | .classpath 5 | .project 6 | .settings      7 |  ##filter databfile、sln file## 8 | *.mdb   9 | *.ldb   10 | *.sln    11 | ##class file## 12 | *.com   13 | *.class   14 | *.dll   15 | *.exe   16 | *.o   17 | *.so  18 | # compression file 19 | *.7z   20 | *.dmg   21 | *.gz   22 | *.iso   23 | *.jar   24 | *.rar   25 | *.tar   26 | *.zip   27 | *.via 28 | *.tmp 29 | *.err 30 | # OS generated files #   31 | .DS_Store   32 | .DS_Store?   33 | ._*   34 | .Spotlight-V100   35 | .Trashes   36 | Icon?   37 | ehthumbs.db   38 | Thumbs.db -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computational-intelligence 2 | 3 | 记录计算智能优化算法的学习笔记,通过阅读论文并复现的形式加深对相关的启发式智能优化的理解。 4 | 5 | 论文复现目前有```matlab```及```python```版,由于个人能力有限,因此难以避免论文代码复现中存在的错误,如有相关不妥之处,还望指正。 6 | 7 | 在每篇的笔记当中,存在部分个人的观点,该观点仅供参考! 8 | 9 | ## 内容目录 10 | 11 | ### 单目标优化 12 | 13 | #### 粒子群优化 14 | 15 | - [经典粒子群优化](粒子群优化算法/经典粒子群优化/粒子群优化一.md)(`OPSO/VPSO,1998`) 16 | - [带收缩因子的粒子群优化](粒子群优化算法/带收缩因子的粒子群优化/一种使用收缩因子的粒子群优化算法.md)(`VPSO,2002`) 17 | - [综合学习粒子群优化](粒子群优化算法/综合学习粒子群优化/综合学习粒子群优化算法.md)(`CLPSO,2006`) 18 | - [自适应粒子群优化](粒子群优化算法/自适应粒子群优化/自适应粒子群优化算法.md)(`APSO,2009`) 19 | - [双中心粒子群优化](粒子群优化算法/双中心粒子群优化/双中心粒子群优化.md)(`DCPSO,2012`) 20 | - [完全受扰的混沌粒子群优化](粒子群优化算法/完全受扰粒子群优化/完全受扰的混沌粒子群优化算法.md)(`TDPSO,2015`) 21 | - [一种基于Sigmoid函数的自适应加权粒子群优化器](粒子群优化算法/一种新的基于Sigmoid函数的自适应加权粒子群优化器/一种基于Sigmoid函数的自适应加权粒子群优化器.md)(`AWPSO,2021`) 22 | 23 | #### 蚁群算法 24 | 25 | - [蚂蚁系统](蚁群优化算法/蚂蚁系统/蚂蚁系统.md)(`AS,1996`) 26 | - [蚁群系统](蚁群优化算法/蚁群系统/蚁群系统.md)(`ACS,1997`) 27 | - [最大最小蚂蚁系统](蚁群优化算法/最大最小蚂蚁系统/最大最小蚂蚁系统.md)(`MMAS,2000`) 28 | - [一种改进的自适应蚁群算法](蚁群优化算法/一种改进的自适应蚁群算法/一种改进的自适应蚁群算法.md)(`IAACO,2021`) 29 | 30 | #### 遗传算法 31 | 32 | - [经典遗传算法](遗传算法/经典遗传算法-GA/经典遗传算法-GA.md)(`GA,1994`) 33 | 34 | #### 狼群算法 35 | 36 | - [狼群算法](狼群算法/狼群算法/狼群算法.md)(`WPA,2013`) 37 | - [灰狼优化算法](狼群算法/灰狼优化算法/灰狼优化算法.md)(`GWO,2014`) 38 | 39 | #### 哈里斯鹰优化算法 40 | 41 | - [哈里斯鹰优化算法](哈里斯鹰优化算法/哈里斯鹰优化算法(HHO)/哈里斯鹰优化算法.md)(`HHO,2019`) 42 | 43 | #### 麻雀算法 44 | 45 | - [麻雀搜索算法](麻雀搜索算法/麻雀搜索算法SSA/麻雀搜索算法.md)(`SSA,2020`) 46 | 47 | #### 萤火虫算法 48 | 49 | - [萤火虫优化](萤火虫算法/萤火虫优化FA/萤火虫算法.md)(`FA,2009`) 50 | -------------------------------------------------------------------------------- /哈里斯鹰优化算法/哈里斯鹰优化算法(HHO)/code/matlab/HHO.m: -------------------------------------------------------------------------------- 1 | %% =============================================================================%% 2 | %% HHO:哈里斯鹰优化算法 (doi:10.1016/j.future.2019.02.028) 3 | % Encoding format:utf-8 4 | % :param N: 种群数目 5 | % :param dim: 求解维度 6 | % :param x_min: 各维度搜索下限 7 | % :param x_max: 各维度搜索上限 8 | % :param iterate_max: 最大迭代次数 9 | % :param fitness: 适应度评价函数 10 | % :return: 11 | % Rabbit_Energy: 对应评价函数在指定迭代下最优适应度 12 | % every_time_Rabbit_Energy:每次迭代的最优适应度 13 | % Rabbit_Location: 最优位置 14 | %% -----------------------------------------------------------------------------%% 15 | 16 | function [Rabbit_Energy, every_time_Rabbit_Energy, Rabbit_Location]=HHO(N, dim, x_max, x_min, iterate_max, fitness) 17 | Rabbit_Location=zeros(1,dim); 18 | Rabbit_Energy=inf; 19 | 20 | %Initialize the locations of Harris' hawks 21 | X = x_min + (x_max - x_min) .* rand(N, dim); 22 | 23 | % 记录每次迭代最优值 24 | every_time_Rabbit_Energy = ones(iterate_max,1); 25 | 26 | iterate = 0; % Loop counter 27 | 28 | while iteratex_max; 32 | FL=X(i,:)=1 50 | %% Exploration: 51 | % Harris' hawks perch randomly based on 2 strategy: 52 | 53 | q=rand(); 54 | rand_Hawk_index = floor(N*rand()+1); 55 | X_rand = X(rand_Hawk_index, :); 56 | if q<0.5 57 | % perch based on other family members 58 | X(i,:)=X_rand-rand()*abs(X_rand-2*rand()*X(i,:)); 59 | elseif q>=0.5 60 | % perch on a random tall tree (random site inside group's home range) 61 | X(i,:)=(Rabbit_Location(1,:)-mean(X))-rand()*((x_max-x_min)*rand+x_min); 62 | end 63 | 64 | elseif abs(Escaping_Energy)<1 65 | %% Exploitation: 66 | % Attacking the rabbit using 4 strategies regarding the behavior of the rabbit 67 | 68 | %% phase 1: surprise pounce (seven kills) 69 | % surprise pounce (seven kills): multiple, short rapid dives by different hawks 70 | 71 | r=rand(); % probablity of each event 72 | 73 | if r>=0.5 && abs(Escaping_Energy)<0.5 % Hard besiege 74 | X(i,:)=(Rabbit_Location)-Escaping_Energy*abs(Rabbit_Location-X(i,:)); 75 | end 76 | 77 | if r>=0.5 && abs(Escaping_Energy)>=0.5 % Soft besiege 78 | Jump_strength=2*(1-rand()); % random jump strength of the rabbit 79 | X(i,:)=(Rabbit_Location-X(i,:))-Escaping_Energy*abs(Jump_strength*Rabbit_Location-X(i,:)); 80 | end 81 | 82 | %% phase 2: performing team rapid dives (leapfrog movements) 83 | if r<0.5 && abs(Escaping_Energy)>=0.5 % Soft besiege % rabbit try to escape by many zigzag deceptive motions 84 | 85 | Jump_strength=2*(1-rand()); 86 | X1=Rabbit_Location-Escaping_Energy*abs(Jump_strength*Rabbit_Location-X(i,:)); 87 | 88 | if fitness(X1)其中$X(t + 1)$是鹰在下一次迭代$t$中的位置向量,$X_{rabbit}(t)$是兔子的位置,$X(t)$是鹰的当前位置向量,$r_1、r_2、r_3、r_4$和$q$是(0,1)内的随机数,每次迭代都会更新,$LB$和$UB$表示变量的上下界,$X_{rand}(t)$是从当前种群中随机选择的鹰,$X_m(t)$是目前的鹰群平均位置。 33 | 34 | 作者提出了一个简单的模型来生成该组的家庭范围$(LB,UB)$内的随机位置。 第一条规则根据随机位置和其他鹰派生成解决方案。 在等式(1)的第二条规则中,有迄今为止最好的位置与组的平均位置的差异加上一个基于变量范围的随机缩放分量,而 $r_3$ 是一个缩放系数,以进一步增加随机 一旦 $r_4$ 接近于 1,规则的性质就会出现类似的分布模式。 在这条规则中,作者向 LB 添加了一个随机缩放的移动长度。 然后,作者为组件考虑了一个随机缩放系数,以提供更多的多样化趋势并探索特征空间的不同区域。 可以构建不同的更新规则,但作者使用了最简单的规则,它能够模仿鹰的行为。 35 | 36 | 鹰群的平均位置是使用公式(2)获得的: 37 | 38 | $$ 39 | X_m(t)=\frac{1}{N}\sum_{i=1}^N X_i(t)\tag{2} 40 | $$ 41 | 42 | >其中 $X_i(t)$ 表示迭代 $t$ 中每只鹰的位置,$N$ 表示鹰的总数。 43 | 44 | ### 2.2 从探索到开发的转变 45 | 46 | $HHO$算法可以从探索转移到利用,然后根据猎物的逃逸能量在不同的利用行为之间变化。 在逃跑的过程中,猎物的能量会大大降低。 为了模拟这一事实,猎物的能量被建模为: 47 | 48 | $$ 49 | E=2E_0(1-\frac{t}{T})\tag{3} 50 | $$ 51 | 52 | >其中$E$表示猎物的逃逸能量,$T$是最大迭代次数,$E_0$是其能量的初始状态。 53 | 54 | 在$HHO$中,$E_0$在每次迭代时在区间(-1,1)内随机变化。当$E_0$的值从0减少到-1时,兔子身体萎靡不振,而当$E_0$的值从0增加到1时,这意味着兔子的身体状况在增强。在迭代期间,动态逃逸能量$E$具有减小的趋势。当逃逸能量$|E|≥1$时,鹰搜索不同的区域以探索兔子的位置,因此,$HHO$执行探索阶段,并且当$|E|<1$时,算法尝试在探索步骤期间探索解的邻域。简而言之,探索发生在$|E|≥1$时,而开发发生在$|E|<1$时。 55 | 56 | ### 2.3 开发阶段 57 | 58 | 在这一阶段,哈里斯鹰通过攻击前一阶段探测到的预定猎物来执行突袭。然而,猎物经常试图逃离危险的环境。因此,在真实的情况下会出现不同的追逐方式。根据猎物的逃跑行为和哈里斯鹰的追逐策略,在$HHO$中提出了四种可能的策略来模拟攻击阶段。猎物总是试图逃离危险的环境。假设$r$是猎物在突袭前成功逃脱$(r <0.5)$或不成功逃脱$(r ≥0.5)$的几率。无论猎物做什么,鹰都会执行一个硬的或软的围攻来抓住猎物。这意味着它们会根据猎物保留的能量,从不同的方向或软或硬地包围猎物。在真实情况下,鹰会越来越靠近目标猎物,通过突袭来增加合作杀死兔子的机会。几分钟后,逃跑的猎物会失去越来越多的能量;然后,鹰强化围攻过程,毫不费力地抓住筋疲力尽的猎物。为了对该策略进行建模并使$HHO$能够在软硬包围过程之间切换,使用了参数$E$。对此,当$|E|≥0.5$时,发生软围攻,当$|E|<0.5$时,发生硬围攻。 59 | 60 | #### 2.3.1 软围攻 61 | 62 | 当$r ≥ 0.5$且$|E| ≥ 0.5$时,兔子仍有足够的能量,并试图通过一些随机的误导性跳跃来逃脱但最终无法逃脱。在这些尝试中,哈里斯的鹰轻轻地包围兔子,使它更加疲惫,然后进行突然袭击。此行为由以下规则建模: 63 | 64 | $$ 65 | X(t+1)=\Delta X(t)-E|JX_{rabbit}(t)-X(t)|\tag{4} 66 | $$ 67 | 68 | $$ 69 | \Delta X(t)=X_{rabbit}(t)-X(t)\tag{5} 70 | $$ 71 | 72 | >其中$X(t)$是兔子的位置向量与迭代t中的当前位置之差,$r_5$是$(0,1)$中的随机数,$J = 2(1-r_5)$表示兔子在整个逃脱过程中的随机跳跃强度。J值在每次迭代中随机变化,以模拟兔子运动。 73 | 74 | #### 2.3.2 硬围攻 75 | 76 | 当$r≥0.5$且$|E|<0.5$时,猎物是极度疲惫,它具有较低的逃逸能量。此外,哈里斯鹰很难包围预定的猎物,以最终执行突袭。在这种情况下,使用等式(6)更新当前位置。 77 | 78 | $$ 79 | X(t+1)=X_{rabbit}(t)-E|\Delta X(t)|\tag{6} 80 | $$ 81 | 82 | #### 2.3.3 渐进式突击的软包围 83 | 84 | 当$E$保持$|E|≥0.5$但$r <0.5$时,兔子有足够的能量成功逃脱,并在突袭前仍构成一次软围攻。这个过程比以前的情况更加智能。 85 | 86 | 为了对猎物的逃脱模式和跳跃运动进行数学建模,在HHO算法中使用了莱维飞行(Levy Flight,LF)概念。LF用于模拟猎物(特别是兔子)在逃跑阶段的真实之字形欺骗性运动,以及鹰在逃跑的猎物周围不规则、突然和快速的俯冲。实际上,鹰在兔子周围进行了几次团队快速俯冲,并试图根据猎物的欺骗性运动逐步纠正它们的位置和方向。这一机制也得到了自然界中其他竞争情况下的真实观察的支持。已经证实,在非破坏性觅食条件下,基于LF的活动是觅食者/捕食者的最佳搜索策略。此外,已经发现基于LF的模式可以在像猴子和鲨鱼这样的动物的追逐活动中检测到。因此,基于低频的运动被用于$HHO$技术的这一阶段。 87 | 88 | 受鹰的真实行为启发,作者认为当它们希望在竞争中捕捉猎物时,它们可以逐步选择最佳的俯冲方式。因此,为了进行软围攻,作者假设鹰群可以根据等式(7)中规则评估(决定)他们的下一步行动: 89 | 90 | $$ 91 | Y=X_{rabbit}(t)-E|JX_{rabbit}(t)-X(t)|\tag{7} 92 | $$ 93 | 94 | 然后,它们将这一动作的可能结果与前一次俯冲进行比较,以检测这是否是一次好的俯冲。如果这是不合理的(当它们看到猎物在做更具欺骗性的动作时),当接近兔子时,它们也会开始做不规则的、突然的、快速的俯冲。作者假设他们将使用公式(8)的规则进行低频模式俯冲: 95 | 96 | $$ 97 | Z=Y+S\times LF(D)\tag{8} 98 | $$ 99 | 100 | >其中$D$是问题的维数,$S$是大小为$1 × D$的随机向量,LF是levy飞行函数,使用等式(9-1)计算: 101 | 102 | $$ 103 | LF(x)=0.01\times \frac{u\times \delta}{|v|^{\frac{1}{\beta}}}\tag{9-1} 104 | $$ 105 | 106 | >其中$u,v$是(0,1)之间的随机数。 107 | 108 | $\delta$的计算方式如下: 109 | 110 | $$ 111 | \delta=\left(\frac{\Gamma(1+\beta)\times sin(\frac{\pi \beta}{2})}{\Gamma(\frac{1+\beta}{2})\times \beta\times 2^{\frac{\beta-1}{2}}}\right)\tag{9-2} 112 | $$ 113 | 114 | >其中$\beta$是一个常数,数值为1.5. 115 | 116 | 因此,在软围攻阶段更新鹰的位置的最终策略按照等式(10)执行。 117 | 118 | $$ 119 | X(t+1)=\left\{\begin{matrix}Y,F(Y)>F(X(t))\\Z,F(Z)\leq F(X(t)) \end{matrix}\right.\tag{10} 120 | $$ 121 | 122 | >其中$Y$和$Z$分别使用公式(7)、(8)计算。 123 | 124 | ### 2.3.4 渐进式突击的硬围攻 125 | 126 | 当|E| <0.5和r <0.5时,兔子没有足够的能量逃跑,在突然扑上来捕捉和杀死猎物之前构筑了一个艰难的包围。在这个步骤中猎物的情况和软围攻中的情况类似,但这一次,老鹰试图减小自己平均位置与逃跑猎物的距离。因此,在硬包围条件下执行以下规则: 127 | 128 | $$ 129 | X(t+1)=\left\{\begin{matrix}Y,F(Y)>F(X(t))\\Z,F(Z)\leq F(X(t)) \end{matrix}\right.\tag{111} 130 | $$ 131 | 132 | >在渐进式突击的硬围攻执行时,等式(11)中$Y$,$Z$分别使用新的规则(12),(13)来执行。 133 | 134 | $$ 135 | Y=X_{rabbit}(t)-E|JX_{rabbit}(t)-X_m(t)|\tag{12} 136 | $$ 137 | 138 | $$ 139 | Z=Y+S\times LF(D)\tag{13} 140 | $$ 141 | 142 | >其中$X_m(t)$利用公式(2)进行计算。 143 | 144 | ### 2.3 算法伪代码 145 | 146 | 算法整体结构及伪代码如下所示: 147 | 148 | ![ref](images/HHO-2.jpg) 149 | 150 | ## 3 代码实现 151 | 152 | >详细代码实现见$code$文件夹,需要说明的是,HHO作者提供了官方的matlab,Java,Python等版本,需要的可自行下载。 153 | 154 | 155 | 156 | ## 参考文献 157 | 158 | [1]Heidari A A, Mirjalili S, Faris H, et al. Harris hawks optimization: Algorithm and applications[J]. Future generation computer systems, 2019, 97: 849-872. 159 | -------------------------------------------------------------------------------- /狼群算法/灰狼优化算法/code/matlab/GWO.m: -------------------------------------------------------------------------------- 1 | %% =============================================================================%% 2 | %% 灰狼算法(DOI: 10.1016/j.advengsoft.2013.12.007) 3 | % coding:陈小斌 4 | % Encoding format:utf-8 5 | % N:种群大小 6 | % dim:问题的维度 7 | % x_max:解空间的上界 8 | % x_min:解空间的下界 9 | % iterate_max:最大迭代次数 10 | % fitnessFunc:测试函数 11 | %% -----------------------------------------------------------------------------%% 12 | function [alpha_value] = GWO(N,dim,x_max,x_min,iterate_max,fitnessFunc) 13 | % 初始化位置 14 | X = rand(N,dim) .* (x_max - x_min) + x_min; 15 | % 初始化 alpha、beta、delta 适应度值,求解最大值问题时将其初始化为 -inf,最小值问题时初始化为 inf 16 | alpha_value = inf; 17 | beta_value = inf; 18 | delta_value = inf; 19 | % 迭代计数器 20 | iterate = 1; 21 | while iterate < iterate_max + 1 22 | % 将越界位置进行相应调整 23 | X(X > x_max) = x_max; 24 | X(X < x_min) = x_min; 25 | 26 | 27 | % 计算每只灰狼的适应度,并更新 alpha、beta、delta 28 | for i = 1:N 29 | fitness_value = fitnessFunc(X(i,:)); 30 | % 更新 alpha 31 | if alpha_value > fitness_value 32 | alpha_value = fitness_value; 33 | alpha = X(i,:); 34 | end 35 | % 更新 beta 36 | if fitness_value > alpha_value && beta_value > fitness_value 37 | beta_value = fitness_value; 38 | beta = X(i,:); 39 | end 40 | % 更新 delta 41 | if fitness_value > alpha_value && fitness_value > beta_value && delta_value > fitness_value 42 | delta_value = fitness_value; 43 | delta = X(i,:); 44 | end 45 | end 46 | 47 | % 计算参数a 48 | a = 2 - 2 * (iterate-1) / iterate_max; 49 | 50 | % 计算 alpha 系数向量 A1 ,公式(3) 51 | A1 = 2 * a .* rand(N,dim) - a; 52 | % 计算 alpha 系数向量 C1 ,公式(4) 53 | C1 = 2 .* rand(N,dim); 54 | 55 | % 计算 D_alpha 公式(5-1) 56 | D_alpha = abs(C1 .*alpha - X); 57 | % 计算 X1 公式(6-1) 58 | X1 = alpha - A1 .* D_alpha; 59 | 60 | 61 | % 计算 beta 系数向量 A2 ,公式(3) 62 | A2 = 2 * a .* rand(N,dim) - a; 63 | % 计算 beta 系数向量 C2 ,公式(4) 64 | C2 = 2 .* rand(N,dim); 65 | 66 | % 计算 D_beta 公式(5-2) 67 | D_beta = abs(C2 .* beta - X); 68 | % 计算 X2 公式(6-2) 69 | X2 = beta - A2 .* D_beta; 70 | 71 | 72 | % 计算 delta 系数向量 A3 ,公式(3) 73 | A3 = 2 * a .* rand(N,dim) - a; 74 | % 计算 delta 系数向量 C3 ,公式(4) 75 | C3 = 2 .* rand(N,dim); 76 | 77 | % 计算 D_delta 公式(5-3) 78 | D_delta = abs(C3 .* delta - X); 79 | % 计算 X3 公式(6-3) 80 | X3 = delta - A3 .* D_delta; 81 | 82 | 83 | % 狼群状态转移,公式(7) 84 | X = (X1 + X2 + X3) ./ 3; 85 | 86 | iterate = iterate + 1; 87 | end 88 | end -------------------------------------------------------------------------------- /狼群算法/灰狼优化算法/images/GWO-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/狼群算法/灰狼优化算法/images/GWO-1.jpg -------------------------------------------------------------------------------- /狼群算法/灰狼优化算法/images/GWO-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/狼群算法/灰狼优化算法/images/GWO-2.jpg -------------------------------------------------------------------------------- /狼群算法/灰狼优化算法/灰狼优化算法.md: -------------------------------------------------------------------------------- 1 | # 灰狼优化算法(Grey Wolf Optimizer) 2 | 3 | ## 1 引言 4 | 5 | 本文描述了一种新的元启发式称为灰狼优化(GWO)的灵感来自灰狼(Canis lupus)。GWO算法模拟了自然界中灰狼的领导阶层和狩猎机制。采用alpha、beta、delta和omega四种类型的灰狼来模拟领导阶层。此外,还实现了狩猎、寻找猎物、包围猎物和攻击猎物三个主要步骤。然后在29个已知的测试函数上对算法进行了基准测试,并与粒子群优化(PSO)、引力搜索算法(GSA)、差分进化(DE)、进化规划(EP)和进化策略(ES)进行了对比研究,验证了算法的结果。结果表明,与这些著名的元启发式算法相比,GWO算法能够提供非常有竞争力的结果。本文还考虑了三个经典的工程设计问题(拉伸/压缩弹簧、焊接梁和压力容器设计),并给出了该方法在光学工程领域的实际应用。经典工程设计问题和实际应用的结果表明,该算法适用于具有未知搜索空间的挑战性问题。 6 | **元启发式算法的优势** 7 | 8 | - 首先,元启发式相当简单。它们的灵感大多来自非常简单的概念。这些灵感通常与物理现象、动物行为或进化概念有关。这种简单性允许计算机科学家模拟不同的自然概念,提出新的元启发法,混合两个或更多的元启发法,或改进当前的元启发法。此外,这种简单性有助于其他科学家快速学习元启发式,并将它们应用到他们的问题中。 9 | - 其次,灵活性是指在不改变算法结构的情况下,元启发式算法对不同问题的适用性。元启发式很容易适用于不同的问题,因为它们大多将问题假定为黑盒。换句话说,对于元启发式,只有系统的输入和输出是重要的。因此,设计师所需要的就是知道如何为元启发式表示他/她的问题。 10 | - 第三,大多数元启发式具有无派生机制。与基于梯度的优化方法相比,元启发式方法是随机优化问题的。优化过程从随机解开始,不需要计算搜索空间的导数来找到最优解。这使得元启发式非常适合于具有昂贵或未知衍生信息的实际问题。 11 | 最后,与传统的优化技术相比,元启发式在避免局部最优方面具有更强的能力。这是由于元启发式的随机特性,它允许它们避免在局部解中停滞,并广泛地搜索整个搜索空间。真实问题的搜索空间通常是未知的,并且非常复杂,有大量的局部最优值,所以元启发式是优化这些具有挑战性的真实问题的很好的选择。 12 | - 最后,与传统的优化技术相比,元启发式在避免局部最优方面具有更强的能力。这是由于元启发式的随机特性,它允许它们避免在局部解中停滞,并广泛地搜索整个搜索空间。真实问题的搜索空间通常是未知的,并且非常复杂,有大量的局部最优值,所以元启发式是优化这些具有挑战性的真实问题的很好的选择。 13 | **元启发式可以分为两种:** 14 | 15 | - 单一解决方案 16 | - 基于种群 17 | 18 | >- 单一解决方案的例如模拟退火,搜索过程从一个候选解决方案开始。然后,在迭代过程中对这个单一的候选解决方案进行改进。 19 | >- 基于种群的元启发式使用一组解决方案(种群)执行优化。在这种情况下,搜索过程从一个随机初始填充(多个解决方案)开始,并且在迭代过程中这个填充会得到增强。 20 | 21 | **与基于单一解决方案的算法相比,基于种群的元启发式有一些优势:** 22 | > 23 | >- 多个候选解决方案共享关于搜索空间的信息,从而导致突然向搜索空间中有前途的部分跳跃。 24 | >- 多个候选解相互帮助,避免局部最优解。 25 | >- 与基于单一解决方案的算法相比,基于群体的元启发式算法通常具有更大的探索意义。 26 | 27 | **元启发式算法中的大多数都使用了群体智能(Swarm Intelligence, SI)相关知识,群体智能类算法具有以下优势:** 28 | > 29 | >- SI算法在迭代过程中保留关于搜索空间的信息,而进化算法(EA)丢弃了前几代的信息。 30 | >- SI算法经常利用内存来保存到目前为止得到的最佳解。 31 | >- 单位制算法通常需要调整的参数较少。 32 | >- 与进化方法(交叉、变异、精英化等)相比,SI算法有更少的运算符。 33 | >- SI算法很容易实现。 34 | 35 | 无论元启发式之间的差异如何,一个共同的特征是将搜索过程划分为两个阶段:**探索和利用**。 36 | 37 | - **探索阶段:** 是指尽可能广泛地调查搜索空间中有希望的区域的过程。为了支持这一阶段,算法需要随机算子对搜索空间进行随机和全局搜索。而 38 | - **开发阶段:** 是指在勘探阶段所获得的有希望区域周围的局部搜索能力。 39 | 40 | ## 2 算法介绍 41 | 42 | ### 2.1 算法生物学描述 43 | 44 | 灰狼(Canis lupus)属于犬科动物。他们有一个非常严格的社会等级制度,如图1所示。 45 | ![ref](images/GWO-1.jpg) 46 | 47 | - **种群领导者-$\alpha$**: 领导者是异性各一,称为$\alpha$。阿尔法狼主要负责决定狩猎、睡觉的地点、醒来的时间等等。$\alpha$狼的决定是由狼群决定的。然而,人们也观察到一些民主的行为,比如一只$\alpha$狼会跟随狼群中的其他狼。在聚会的时候,整个狼群都会把尾巴垂下来以示对首领的认可。$\alpha$狼也被称为统治狼,因为他/她的命令应该由整个狼群来执行。$\alpha$狼只允许在狼群中交配。有趣的是,$\alpha$不一定是团队中最强大的成员,但在管理团队方面是最好的。这表明一个狼群的组织和纪律比它的力量重要得多。 48 | - **灰狼第二级-$\beta$**:$\beta$狼是一种从属的狼,在决策或其他群体活动中帮助首领。$\beta$狼可以是雄性或雌性,他/她可能是成为$\alpha$狼的最佳人选,以防其中一只$\alpha$狼去世或变得非常老。$\beta$狼应该尊重$\alpha$狼,但也要指挥其他低级狼。它扮演着首领的顾问和狼群的纪律执行者的角色。$\beta$加强了$\alpha$在整个族群中的命令,并向$\alpha$提供反馈。 49 | - **灰狼最低等级-$\omega$**:$\omega$是替罪羊的角色。$\omega$狼总是要服从于其他所有的狼。它们是最后被允许进食的狼群。看起来$\omega$在族群中并不是一个重要的个体,但据观察,如果失去$\omega$,整个族群将面临内部斗争和问题。这是由于$\omega$对所有狼人暴力和挫折的发泄。这有助于满足整个族群的需求并维持主导结构。在某些情况下,$\omega$还是族群中的保姆。 50 | - **灰狼的其他等级-$\delta$**:如果一只狼不是$\alpha$、$\beta$或$\omega$,他/她被称为下属(或在某些参考文献中称为$\delta$)。$\delta$狼不得不屈从于阿尔法和贝塔,但它们主宰着$\omega$。侦察兵、哨兵、长老、猎人和看护者都属于这一类。侦察兵负责观察领地的边界,并在任何危险情况下警告狼群。哨兵保护并保证族群的安全。长者是有经验的狼人,他们曾经是$\alpha$狼或$\beta$狼。猎人帮助$\alpha$和$\beta$狩猎猎物,并为狼群提供食物。最后,看护人负责照顾狼群中虚弱、生病和受伤的狼。 51 | 52 | **除了狼的社会等级,群居狩猎是灰狼另一种有趣的社会行为。灰狼狩猎的主要阶段如下:** 53 | 54 | - 追踪,追逐,接近猎物。 55 | - 追逐,包围和骚扰猎物直到它停止移动。 56 | - 攻击猎物。 57 | 58 | ### 2.2 算法的数学模型 59 | 60 | #### 2.2.1 等级模型 61 | 62 | 为了在设计 GWO 时对狼的社会等级进行数学建模,我们将最适合的解决方案视为 $\alpha$ (a)。 因此,第二个和第三个最佳解决方案分别命名为 $\beta$ (b) 和 $\delta$ (d)。 其余的候选解被假定为 $\omega$ (x)。 在 GWO 算法中,搜索(优化)由 a、b 和 d 引导。 x 狼跟随这三只狼。 63 | 64 | >在这里,即将当前搜索到的解决方案使用对应问题模型进行评价,并将评价位置按适应度进行排序,使用前三个最优解对种群中的其余狼进行引导。 65 | 66 | #### 2.2.2 包围猎物 67 | 68 | 灰狼在狩猎过程中会包围猎物。包围猎物的移动方程如下: 69 | $$ 70 | \vec{D}=|\vec{C}\cdot\vec{X_p}(t)-\vec{X_t}|\tag{1} 71 | $$ 72 | 73 | $$ 74 | \vec{X}(t+1)=\vec{X_p}(t)-\vec{A}\cdot\vec{D}\tag{2} 75 | $$ 76 | 77 | >其中$t$表示当前迭代,$\vec{A}$和$\vec{C}$是系数向量,$\vec{X_p}$是猎物的位置向量,$\vec{X}$表示灰狼的位置向量。 78 | 79 | 向量$\vec{A}$和$\vec{C}$计算公式如下: 80 | 81 | $$ 82 | \vec{A}=2\vec{a}\cdot\vec{r_1}-\vec{a}\tag{3} 83 | $$ 84 | $$ 85 | \vec{C}=2\cdot\vec{r_2}\tag{4} 86 | $$ 87 | 88 | >其中$\vec{a}$的分量在迭代过程中从 2 线性减少到 0,而$r_1、r_2$是 [0, 1] 中的随机向量。 89 | 90 | #### 2.2.3 捕食 91 | 92 | 灰狼具有识别猎物位置并包围它们的能力。 狩猎通常由$\alpha$引导。$\beta$和$\delta$也可能偶尔参与狩猎。 然而,在抽象的搜索空间中,我们不知道最佳位置(猎物)的位置。 为了在数学上模拟灰狼的狩猎行为,作者假设$\alpha$(最佳候选解决方案)$\beta$和$\delta$对猎物的潜在位置有更好的了解。 因此,我们保存目前获得的前三个最佳解决方案,并强制其他搜索代理(包括 $\omega$)根据最佳搜索代理的位置更新他们的位置。 在这方面提出以下公式。 93 | 94 | $$ 95 | \begin{cases} 96 | \vec{D_{\alpha}}=|\vec{C_1}\cdot\vec{X_{\alpha}}-\vec{X}|\\ 97 | \vec{D_{\beta}}=|\vec{C_2}\cdot\vec{X_{\beta}}-\vec{X}|\\ 98 | \vec{D_{\delta}}=|\vec{C_3}\cdot\vec{X_{\delta}}-\vec{X}|\\ 99 | \end{cases}\tag{5} 100 | $$ 101 | $$ 102 | \begin{cases} 103 | \vec{X_1}=\vec{X_{\alpha}}-\vec{A_1}\cdot\vec{D_{\alpha}}\\ 104 | \vec{X_2}=\vec{X_{\beta}}-\vec{A_2}\cdot\vec{D_{\beta}}\\ 105 | \vec{X_3}=\vec{X_{\delta}}-\vec{A_3}\cdot\vec{D_{\delta}}\\ 106 | \end{cases}\tag{6} 107 | $$ 108 | $$ 109 | \vec{X}(t+1)=\frac{\vec{X_1}+\vec{X_2}+\vec{X_3}}{3}\tag{7} 110 | $$ 111 | 112 | > 113 | 114 | #### 2.2.4 攻击猎物(剥削) 115 | 116 | 当猎物停止移动时,灰狼就会攻击猎物,从而结束捕猎。为了建立接近猎物的数学模型,我们降低了$\vec{a}$的值。根据公式(3)可知$\vec{A}$的波动范围也随着$\vec{a}$减小。换句话说$\vec{A}$是区间$[-2a, 2a]$内的一个随机值,其中$a$在迭代过程中从2减少到0。当$\vec{A}$的随机值为[1,1]时,搜索代理的下一个位置可以是其当前位置与被捕食者位置之间的任意位置。 117 | 118 | >上面是原文对于攻击猎物的描述,当我自己读这一段时,发现以下几个问题,第一,$\vec{a}$是一个向量,而非实值,因此描述向量$\vec{A}$的范围有点问题;第二,按照公式(3),用作者所描述的,那么$\vec{A}$的取值范围也应该是$[-a,2a]$ 119 | 120 | ![ref](images/GWO-2.jpg) 121 | 122 | GWO 算法的伪代码如上图所示。 为了了解 GWO 在理论上如何解决优化问题,可能需要注意以下几点: 123 | 124 | - 提议的社会等级有助于 GWO 保存迄今为止在迭代过程中获得的最佳解决方案。 125 | - 提议的环绕机制定义了围绕解决方案的圆形邻域,该邻域可以扩展到更高维度作为超球体。 126 | - 随机参数 A 和 C 帮助候选解具有不同随机半径的超球体。 127 | - 所提出的狩猎方法允许候选解决方案定位猎物的可能位置。 128 | - 探索和开发由 a 和 A 的自适应值保证。 129 | - 参数 a 和 A 的自适应值允许 GWO 在探索和开发之间平滑过渡。 130 | - 随着 A 的减小,一半的迭代用于探索$(|A|\geq 1)$,另一半用于开发$(|A| < 1)$。 131 | - GWO 只有两个主要参数需要调整(a 和 C)。 132 | 133 | ### 2.3 代码回溯 134 | 135 | 在作者的论文中,对于如何具体实现$GWO$的流程和要求没有进行详细描述,只是给出了较为重要的几个公式。所幸作者给出了源代码,据此写下本小节。本人才疏学浅,如有错误,请指正! 136 | 137 | #### 2.3.1 位置初始化 138 | 139 | 在$GWO$中,灰狼位置初始化与搜索空间有关,具体公式如下: 140 | 141 | $$ 142 | position_i^d=rand\cdot (x_{max}^d-x_{min}^d) + x_{min}^d\tag{8} 143 | $$ 144 | >其中$position_i^d$为第$i$只灰狼维度$d$的位置,$rand$为(0,1)之间的均匀随机数,$x_{max}^d$为第$d$维的上限解空间,$x_{min}^d$为第$d$维的下限解空间。 145 | 146 | #### 2.3.2 位置限制 147 | 148 | 与$PSO$类似,在$GWO$中也需要对跨越边界的维度进行处理,处理方式也一样,将对应出界的维度拉回最近的边界。公式如下: 149 | 150 | $$ 151 | \begin{cases} 152 | position_i^d=x_{max}^d&if\quad position_i^d>x_{max}^d\\ 153 | position_i^d=x_{min}^d&if\quad position_i^d>x_{min}^d 154 | \end{cases}\tag{9} 155 | $$ 156 | 157 | #### 2.3.3 状态转移 158 | 159 | 1. 按照算法的数学模型,从当前狼中挑选出$\alpha,\beta,\delta$狼,即将适应度前三的狼命名为$\alpha,\beta,\delta$。 160 | >这里需要特别注意,$\alpha,\beta,\delta$保存的是迭代过程中适应度前三的灰狼位置,即全局历史前三的最优位置。 161 | 2. 按照公式(9)计算参数$a$(参数$a$随迭代次数在2~0线性递减):$$a=2-\frac{2\times iterate}{iterate_{max}}\tag{10}$$ 162 | >其中$iterate$为当前迭代次数,由于$a$的取值范围为一开始为2,因此我们需要使第一次公式(10)分子为0,$iterate_{max}$为最大迭代次数。 163 | > 164 | 3. 按照公式(3)、(4)计算$\alpha,\beta,\delta$狼对应的系数$\vec{A}、\vec{C}$,在原文公式中给出的是矩阵系数的直接计算公式,实际上内部计算公式如下公式(11)、(12)所示:$$A_i^d=2a\cdot rand-a\tag{11}$$$$C_i^d=2\cdot rand\tag{12}$$ 165 | >即矩阵$\vec{A}、\vec{C}$是根据公式(3)、(4)计算而来,而公式中的矩阵$\vec{r}$是一个随机矩阵,即矩阵中的所有维度都是随机生成的。 166 | >此外,公式(3)、(4)中的向量$\vec{a}$可以把它看作是一个各维度都相同的向量,但是在矩阵运算中,标量是可以直接和向量或者矩阵直接运算的。因此,向量$\vec{a}$就可以被看作参数$a$。 167 | > 168 | 4. 按照公式(5)、(6)计算$D_{\alpha}、D_{\beta}、D_{\delta}$和$X_1、X_2、X_3$ 169 | 5. 按照公式(7)计算本次迭代位置 170 | 171 | ## 3 算法实现 172 | 173 | 在实现代码过程中,还是存在一个疑虑,在作者给出的代码中,历史前三的$\alpha,\beta,\delta$狼是根据适应度值进行排序的,倘若存在位置不一样,但是适应度值一样的情形,那么依旧会忽略这些位置。因此严格意义上来说,$\alpha,\beta,\delta$狼是按照适应度值排序的三类狼。 174 | 175 | 详情见code文件夹下的对应代码。 176 | 177 | ## 4 参考文献 178 | 179 | [1] Sm A , Smm B , Al A . Grey Wolf Optimizer[J]. Advances in Engineering Software, 2014:46–61. 180 | -------------------------------------------------------------------------------- /狼群算法/狼群算法/code/matlab/WPA.m: -------------------------------------------------------------------------------- 1 | %% =============================================================================%% 2 | %% 狼群算法(DOI:10.3969/j.issn.1001-506X.2013.11.33) 3 | % coding:陈小斌 4 | % Encoding format:utf-8 5 | % N:种群大小 6 | % dim:问题的维度 7 | % x_max:解空间的上界 8 | % x_min:解空间的下界 9 | % iterate_max:最大迭代次数 10 | % fitnessFunc:测试函数 11 | %% -----------------------------------------------------------------------------%% 12 | function [result] = WPA(N,dim,x_max,x_min,iterate_max,fitnessFunc) 13 | alpha = 4; 14 | T_max = 20; 15 | omega = 500; 16 | S = 1000; 17 | beta = 6; 18 | h = dim; 19 | % 初始化智能行为的步长,由于一般的问题种各维度求解区间一致,因此不用单独求解每个维度的步长, 20 | % 但是为了保证和论文原文的一致性,这里还是使用数组保存各维度的步长, 21 | step_a = ones(1,dim) .* (abs(x_max - x_min)/S); 22 | step_b = step_a * 2; 23 | step_c = step_a / 2; 24 | 25 | % 初始化种群位置 26 | X = x_min + (x_max - x_min) .* rand(N,dim); 27 | 28 | % 存储各位置的适应度 29 | fitness_Value = ones(N,1) * inf; 30 | % 获取各适应度值 31 | for i=1:N 32 | fitness_Value(i) = fitnessFunc(X(i,:)); 33 | end 34 | 35 | iterate = 1; 36 | 37 | while iterate < iterate_max + 1 38 | % 探狼数目 39 | S_num = randi([ceil(N/(alpha+1)),floor(N/alpha)]); 40 | % 猛狼数目 41 | M_num = N - S_num -1; 42 | % 弱肉强食死亡狼数目 43 | R = randi([ceil(N/(2 * beta)),floor(N/beta)]); 44 | 45 | 46 | % 对狼所在位置按照适应度进行排列 47 | [~,Original_index] = sort(fitness_Value); 48 | % 获取探狼索引 49 | detective_wolf_index = Original_index(2:S_num+1); 50 | % 获取猛狼索引 51 | Fierce_wolf_index = Original_index(S_num+2:N); 52 | 53 | %% 游走行为 54 | [X, fitness_Value] = WanderingBehavior(X, T_max, S_num, h, fitness_Value, detective_wolf_index, step_a, fitnessFunc); 55 | 56 | 57 | % 在原文中 d_near 的计算是在非对称区间维度进行求解,但是一般公开的测试函数都是对称求解区间, 58 | % D = size(x_max, 1); 59 | % d_near = sum((x_max - x_min)) /(D * omega); 60 | % 因此这里使用对称求解区间,稍微改动一下公式 61 | d_near = (x_max - x_min) / omega; 62 | %% 召唤行为 63 | [X, fitness_Value] = SummoningBehavior(X, M_num, d_near, fitness_Value, Fierce_wolf_index, step_b, fitnessFunc); 64 | 65 | %% 围攻行为 66 | [X, fitness_Value] = SiegeBehavior(X, N, fitness_Value, step_c, fitnessFunc); 67 | 68 | %% 适者生存机制 69 | [X, fitness_Value] = FittestSurvive(X, N, dim, R, x_max, x_min, fitness_Value, fitnessFunc) 70 | 71 | iterate = iterate + 1; 72 | end 73 | 74 | result = min(fitness_Value); 75 | end 76 | 77 | 78 | function [wolf_position, fitness_Value] = WanderingBehavior(wolf_position, T_max, S_num, h, fitness_Value, detective_wolf_index, step_a, fitnessFunc) 79 | %myFun - Description 80 | % 81 | % Syntax: X = myFun(input) 82 | % 83 | % Long description 84 | %% 游走行为 85 | % 找到头狼位置 86 | head_wolf_index = find(fitness_Value==min(fitness_Value), 1); 87 | % 获取头狼适应度值 88 | head_wolf_value = fitness_Value(head_wolf_index); 89 | for j = 1:S_num 90 | % 游走行为是每只探狼往不同方向上行走并记录,使用最优的保存下来 91 | for i=1:T_max 92 | XJ_every_h = wolf_position(detective_wolf_index(j),:) + sin(2*pi*(1:h)'/h) .* step_a; 93 | % 对 h 个方向上的适应度进行评估,保留最好的适应度作为探狼 j 的位置 94 | for k=1:h 95 | if fitness_Value(detective_wolf_index(j)) > fitnessFunc(XJ_every_h(k,:)); 96 | wolf_position(detective_wolf_index(j),:) = XJ_every_h(k,:); 97 | fitness_Value(detective_wolf_index(j)) = fitnessFunc(XJ_every_h(k,:)); 98 | end 99 | end 100 | % 如果探狼已经出现优于头狼适应度位置的现象,则停止该探狼停止游走 101 | if min(fitness_Value) < head_wolf_value 102 | % 因为头狼是所有狼适应度最小的,因此如若此时出现适应度比头狼小,则必定是当前探狼 103 | % 更新头狼的适应度值,由于游走并不会使用到头狼位置,因此不予以保存 104 | head_wolf_value = min(fitness_Value); 105 | % 结束当前探狼的游走 106 | break; 107 | end 108 | end 109 | end 110 | end 111 | 112 | 113 | function [wolf_position, fitness_Value] = SummoningBehavior(wolf_position,M_num, d_near, fitness_Value, Fierce_wolf_index, step_b, fitnessFunc) 114 | %myFun - Description 115 | % 116 | % Syntax: output = myFun(input) 117 | % 118 | % Long description 119 | 120 | % 找到头狼位置 121 | head_wolf_index = find(fitness_Value==min(fitness_Value), 1); 122 | head_walf_position = wolf_position(head_wolf_index, :); 123 | head_wolf_value = fitness_Value(head_wolf_index); 124 | 125 | %% 召唤行为 126 | for i=1:M_num 127 | d_is = sum(abs((wolf_position(Fierce_wolf_index(i),:) - head_walf_position))); 128 | %% 这两个 while 循环的合理性说实话是很难去界定的,理论来说,只有找到了更好的位置,才能跳出两个循环 129 | % 但倘若是没找到,则一样是死循环 130 | while d_is > d_near 131 | % 这个循环很奇妙,倘若猛狼i按照这也的召唤行为已知找不到比当前头狼位置好的位置,那就是个死循环 132 | % 在这个算法中你可以发现很多类似的地方,就是在算法内部狼其实走了很多步,因此时间复杂度也无法计算 133 | % 比较好的改变是将论文流程图中的循环改成判断 134 | %% 不合理的实现 135 | while fitness_Value(Fierce_wolf_index(i)) > head_wolf_value 136 | wolf_position(Fierce_wolf_index(i),:) = wolf_position(Fierce_wolf_index(i),:) + step_b .* (head_walf_position - wolf_position(Fierce_wolf_index(i),:)) ./ abs(head_walf_position - wolf_position(Fierce_wolf_index(i),:)); 137 | fitness_Value(Fierce_wolf_index(i)) = fitnessFunc(wolf_position(Fierce_wolf_index(i),:)); 138 | end 139 | % 跳出当前循环,说明探狼i已经找到更好位置(至少不输于当前头狼位置) 140 | head_walf_position = wolf_position(Fierce_wolf_index(i),:); 141 | head_wolf_value = fitness_Value(Fierce_wolf_index(i)); 142 | 143 | % 其实判断 d_is>d_near 是个伪命题,因为当跳出 Yi>Ylead 循环之后,就意味着当前猛狼i成为新头狼 144 | % 而 d_is 是计算当前猛狼i和当前头狼的距离,两者是一模一样的, d_is 自然是零 145 | % d_is = sum(abs((wolf_position(Fierce_wolf_index(i),:) - head_walf_position))); 146 | break; 147 | d_is = sum(abs((wolf_position(Fierce_wolf_index(i),:) - head_walf_position))); 148 | end 149 | end 150 | end 151 | 152 | 153 | function [wolf_position, fitness_Value] = SiegeBehavior(wolf_position, N, fitness_Value, step_c, fitnessFunc) 154 | %myFun - Description 155 | % 156 | % Syntax: output = myFun(input) 157 | % 158 | % Long description 159 | 160 | % 更新头狼位置 161 | % 对狼所在位置按照适应度进行排列 162 | [~,Original_index] = sort(fitness_Value); 163 | % 获取头狼索引 164 | head_wolf_index = Original_index(1); 165 | % 获取头狼位置 166 | head_walf_position = wolf_position(head_wolf_index, :); 167 | %==头狼和对狼所在位置按照适应度进行排列在结束召唤行为前已经完成更新==% 168 | % 获取其他狼位置(包含除头狼外的所有狼) 169 | other_wolf_index = Original_index(2:N); 170 | 171 | %% 围攻行为 172 | lamda = -1 + 2 * rand; 173 | wolf_position(other_wolf_index,:) = wolf_position(other_wolf_index,:) + lamda * step_c .* abs(head_walf_position - wolf_position(other_wolf_index,:)); 174 | 175 | % 获取围攻行为后各适应度值 176 | for i=1:N 177 | fitness_Value(i) = fitnessFunc(wolf_position(i,:)); 178 | end 179 | end 180 | 181 | 182 | function [wolf_position, fitness_Value] = FittestSurvive(wolf_position, N, dim, R, x_max, x_min, fitness_Value, fitnessFunc) 183 | %myFun - Description 184 | % 185 | % Syntax: output = myFun(input) 186 | % 187 | % Long description 188 | % 对狼所在位置按照适应度进行排列 189 | [~,Original_index] = sort(fitness_Value); 190 | %% 计算淘汰狼的数目 191 | dead_wolf_index = Original_index(N - R + 1:N); 192 | % 淘汰狼重新生成 193 | wolf_position(dead_wolf_index,:) = x_min + (x_max - x_min) .* rand(R,dim); 194 | % 重新计算各适应度值 195 | for i=1:N 196 | fitness_Value(i) = fitnessFunc(wolf_position(i,:)); 197 | end 198 | end -------------------------------------------------------------------------------- /狼群算法/狼群算法/images/WPA-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/狼群算法/狼群算法/images/WPA-1.jpg -------------------------------------------------------------------------------- /狼群算法/狼群算法/images/WPA-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/狼群算法/狼群算法/images/WPA-2.jpg -------------------------------------------------------------------------------- /狼群算法/狼群算法/狼群算法.md: -------------------------------------------------------------------------------- 1 | # 狼群算法(Wolf Pack Algorithm,WPA) 2 | 3 | ## 1 引言 4 | 5 | 基于狼群群体智能,模拟狼群捕食行为及其猎物分配方式,抽象出游走、召唤、围攻3种智能行为以及“胜者为王”的头狼产生规则和“强者生存”的狼群更新机制,提出一种新的群体智能算法———狼群算法(Wolf Pack Algorithm,WPA)。 6 | 7 | 狼群中有着明显的阶级,并且每一个阶级都有其明确的社会分工,它们团结协作为狼群的生存与发展承担着各自的责任。狼群中分别有:头狼、探狼、猛狼角色,各角色特点及猎物分配规则如下: 8 | 9 | - 头狼: 10 | 11 | >头狼始终是狼群中最具智慧和最凶猛的,是在“弱肉强食、胜者为王”式的残酷竞争中产生的首领。它不 断地根据狼群所感知到的信息进行决策,负责整个狼群的 指挥和把关维护,既要避免狼群陷入危险境地又要指挥狼 群以期尽快地捕获猎物。 12 | - 探狼: 13 | 14 | >寻找猎物时,狼群不会全体出动而是派出少数精 锐的探狼在猎物的可能活动范围内游猎,根据空气中猎物 留下的气味进行自主决策,气味越浓表明狼离猎物越近,探 狼始终就朝着气味最浓的方向搜寻。 15 | - 猛狼: 16 | 17 | >一旦探狼发现猎物踪迹,就会立即向头狼报告, 头狼视情通过嚎叫召唤周围的猛狼来对猎物进行围攻。周 围的猛狼闻声则会自发地朝着该探狼的方向奔袭,向猎物 进一步逼近。 18 | - 猎物分配规则: 19 | 20 | >捕获猎物后,狼群并不是平均分配猎物,而是按“论功行赏、由强到弱”的方式分配,即先将猎物 分配给最先发现、捕到猎物的强壮的狼,而后再分配给弱小 的狼。尽管这种近乎残酷的食物分配方式会使得少数弱狼 由于食物缺乏而饿死,但此规则可保证有能力捕到猎物的 狼获得充足的食物进而保持其强健的体质,在下次捕猎时 仍可顺利地捕到猎物,从而维持着狼群主体的延续和发展。 21 | 22 | 狼群捕猎模型如下: 23 | 24 | ![ref](images/WPA-1.jpg) 25 | 26 | ## 2 算法介绍 27 | 28 | ### 2.1 问题定义 29 | 30 | 设狼群的猎场空间为一个$N\times D$的欧式空间,其中$N$为狼群中人工狼总数,$D$为待寻优的变量数。某一人工狼$i$的状态可表示为$X_i=(x_{i1},x_{i2},\cdots,x_{id})$,其中 $x_{id}$ 为 $i$ 匹人工狼在欲寻优的第$d(d=1,2,\cdots,D)$维变量空间中所处位置;人工狼所感知到的猎物气味浓度为$Y=f(X)$,其中 $Y$ 就是目标函数值;人工狼 $p$ 和 $q$ 之间的距离定义为其状态 向量间的曼哈顿(Manhattan)距离$L(p,q) = \sum_{d=1}^D|x_{pd}-x_{qd}|$,当然也可依据具体问题选用其他的距离度量。另外,由于实际中极大与极小值问题之间可相互转换,为论述方便以下皆以极大值问题进行讨论。 31 | 32 | ### 2.2 智能行为和规则的描述 33 | 34 | 头狼、探狼和猛狼间的默契配合成就了狼群近乎完美的捕猎行动,而“由强到弱”的猎物分配又促使狼群向最有 可能再次捕获到猎物的方向繁衍发展。将狼群的整个捕猎 活动抽象为3种智能行为(即游走行为、召唤行为、围攻行为)以及“胜者为王”的头狼产生规则和“强者生存”的狼群 更新机制。 35 | 36 | 1. **头狼产生规则**:初始解空间中,具有最优目标函数值的人工狼即为头狼;在迭代过程中,将每次迭代后最优狼的目标函数值与前一代中头狼的值进行比较,若更优则对头狼位置进行更新,若此时存在多匹的情况,则随机选一 匹成为头狼。头狼不执行3种智能行为而直接进入下次迭代,直到它被其他更强的人工狼所替代。 37 | 38 | 2. **游走行为**:将解空间中除头狼外最佳的 $S_{num}$ 匹人工狼视为探狼,在解空间中搜索猎物,$S_{num}$ 随机取 $[n/(\alpha+1),n/\alpha]$ 之间的整数,$α$为探狼比例因子。探狼 $i$ 首先感知空气中的猎物气味,即计算该探狼当前位置的猎物气味浓度 $Y_i$。若 $Y_i$ 大于头狼所感知的猎物气味浓度 $Y_{lead}$,表明猎物离探狼 $i$ 已相对较近且该探狼最有可能捕获猎物。于是 $Y_{lead}=Y_i$,探狼 $i$ 替代头狼并发起召唤行为;若 $Y_iY_{lead}$ 或游走次数 $T$ 达到最大游走次数 $T_{max}$. 42 | 43 | >需要说明的是由于每匹探狼的猎物搜寻方式存在差异,$h$ 的取值是不同的,实际中可依据情况取 $[h_{min},h_{max}]$ 间的随机整数,$h$ 越大探狼搜寻得越精细但同时速度也相对较慢。 44 | 45 | 3. **召唤行为**:头狼通过嚎叫发起召唤行为,召集周围的 $M_{num}$ 匹猛狼向头狼所在位置迅速靠拢,其中 $M_{num}=n-S_{num}-1$ ;听到嚎叫的猛狼都以相对较大的奔袭步长 $step_b$ 快速逼近头狼所在的位置。则猛狼 $i$ 第 $k+1$ 次迭代时,在第 $d$ 维变量空间中所处的位置为:$$x_{id}^{k+1}=x_{id}^k+step_b\cdot(g_d^k-x_{id}^k)/|g_d^k-x_{id}^k|\tag{2} 46 | $$式中,$g_d^k$ 为第 $k$ 代群体头狼在第 $d$ 维空间中的位置。式(2)由2部分组成,前者为人工狼当前位置,体现狼的围猎基础;后者表示人工狼逐渐向头狼位置聚集的趋势,体现头狼对狼群的指挥。 47 | 奔袭途中,若猛狼 $i$ 感知到的猎物气味浓度 $Y_i>Y_{lead}$,则 $Y_{lead}=Y_i$,该猛狼转化为头狼并发起召唤行为;若 $Y_i召唤行为体现了狼群的信息传递与共享机制,并融入 了社会认知观点,通过狼群中其他个体对群体优秀者的“追 随”与“响应”,充分显示出算法的社会性和智能性。 51 | 52 | 4. **围攻行为**:经过奔袭的猛狼已离猎物较近,这时猛狼要联合探狼对猎物进行紧密地围攻以期将其捕获。这里将离猎物最近的狼,即头狼的位置视为猎物的移动位置。具体地,对于第 $k$ 代狼群,设猎物在第 $d$ 维空间中的位置为 $G_d^k$,则狼群的围攻行为可用方程(4)表示$$x_{id}^{k+1}=x_{id}^k+\lambda\cdot step_c^d\cdot|G_d^k-x_{id}^k|\tag{4}$$式中,$λ$ 为[-1,1]间均匀分布的随机数;$step_c$ 为人工狼 $i$ 执行围攻行为时的攻击步长。若实施围攻行为后人工狼感知到的猎物气味浓度大于其原位置状态所感知的猎物气味浓度,则更新此人工狼的位置,若不然,人工狼位置不变。 53 | 54 | 设待寻优第d个变量的取值范围为 $[min_d,max_d]$,则3种智能行为中所涉及到游走步长 $step_a$、奔袭步长 $step_b$、 攻击步长 $step_c$ 在第$d$ 维空间中的步长存在如下关系:$$step_a^d=step_b^d/2=2\cdot step_c^d=|max_d-min_d|/S\tag{5}$$式中,$S$ 为步长因子,表示人工狼在解空间中搜寻最优解的精细程度。 55 | 56 | 5. **“强者生存”的狼群更新机制**:猎物按照“由强到弱”的原则进行分配,导致弱小的狼会被饿死。即在算法中去除目标函数值最差的 $R$ 匹人工狼,同时随机产生 $R$ 匹人工狼。$R$ 越大则新产生的人工狼越多,有利于维护狼群个体的多样性,但若 $R$ 过大算法就趋近于随机搜索;若 $R$ 过小,则不利于维护狼群的个体多样性,算法开辟新的解空间的能力减弱。由于实际捕猎中捕获猎物的大小、数量是有差别的,进而导致了不等数量的弱狼饿死。因此,这里 $R$ 取 $[n/(2\times \beta),n/\beta]$ 之间的随机整数,$β$ 为群体更新比例因子。 57 | 58 | ### 2.3 算法描述 59 | 60 | 狼群算法的具体步骤如下。 61 | 62 | >- 步骤1: 数值初始化。初始化狼群中人工狼位置 $X_i$ 及种群数目 $N$,最大迭代次数 $k_{max}$,探狼比例因子 $α$,最大游走次数 $T_{max}$,距离判定因子 $\omega$,步长因子 $S$,更新比例因子 $\beta$。 63 | > 64 | >--- 65 | > 66 | >- 步骤2: 选取最优人工狼为头狼,除头狼外最佳的 $S_{num}$匹人工狼为探狼,其余狼作为猛狼。并执行游走行为,直到某只探狼 $i$ 侦察到的猎物气味浓度 $Y_i$,大于头狼所感知的猎物气味浓度 $Y_{lead}$或达到最大游走次数 $T_{max}$,则转步骤3。 67 | > 68 | >--- 69 | > 70 | >- 步骤3: 人工猛狼据式(2)向猎物奔袭,若途中猛狼感知的猎物气味浓度 $Y_i>Y_{lead}$,则 $Y_{lead}=Y_i$ ,替代头狼并发起召唤行为;若 $Y_i 72 | >--- 73 | > 74 | >- 步骤4: 按式(4)对参与围攻行为的人工狼的位置进行更新,执行围攻行为。 75 | > 76 | >--- 77 | > 78 | >- 步骤5: 按“胜者为王”的头狼产生规则对头狼位置进行更新;再按照“强者生存”的狼群更新机制进行群体更新。 79 | > 80 | >--- 81 | > 82 | >- 步骤6: 判断是否达到优化精度要求或最大迭代次数 $k_{max}$,若达到则输出头狼的位置,即所求问题的最优解,否则转步骤2。 83 | 84 | 综上,$WPA$的流程图如图2所示。 85 | ![ref](images/WPA-2.jpg) 86 | 87 | >- 从原文的描述以及流程图来看,狼群的分类是在每一次迭代中进行的,但是在描述当中,头狼位置又是实时变换的,因此每一次头狼位置发生改变后,还是需要每一次对狼群进行评估,并重新划分探狼,猛狼。 88 | >- 另外,流程图描述的是单只狼的行为,即该算法是单只狼一步一步轮流操作,而非并行同时搜索。 89 | 90 | ### 2.4 参数设置 91 | 92 | >- 探狼比例因子$α=4$ 93 | >- 最大游走次数$T_{max}=20$ 94 | >- 距离判定因子$\omega=500$ 95 | >- 步长因子$S=1000$ 96 | >- 更新比例因子$β=6$ 97 | 98 | ## 3 算法实现 99 | 100 | 在算法实现过程中,有以下几点需要说明: 101 | 102 | - 在算法描述中,探狼数目$S_{num}$、猛狼数目$M_{num}$以及最后的优胜劣汰狼的数目$R$,并未说明是在一开始计算好,还是每次迭代的时候都随机取值。 103 | 104 | >关于这一问题,在实验过程中发现,每次迭代时随机取值效果会更好。 105 | 106 | - 在$WPA$描述中,内部也存在迭代,但是猛狼和探狼更新上迭代计算公式(2)和(4)是根据前后迭代次数来描述的。按照流程图理解,每一代应该是通过最终终止条件来判断。 107 | 108 | >针对这一问题,个人认为可以直接看作前后两者存在简单更新,不必太在意右上角迭代数目标识 109 | 110 | - 在算法描述中,对于头狼的描述是全局最优位置为头狼,但是对于其他狼却没有明确说明,同时在文中作者**将解空间中除头狼外最佳的 $S_{num}$ 匹人工狼视为探狼**,因此在该文的描述中,自始自终都不需要使用另外的空间存储历史最优位置,因为全局最优位置是不需要进行移动,只需要引导其他狼移动。但同时也暴露出一个巨大问题,所有的狼并非都会受到头狼吸引,探狼只会在周围游走,只有猛狼在召唤和围攻行为时才会被头狼引导。 111 | 112 | 最后,本代码仅仅是个人在阅读文献理解编写而成,因此存在倘若存在错误也是不可避免,如果实验结果与参考文献不一致,请以作者为准! 113 | 114 | 代码详情见$code$文件夹。 115 | 116 | >由于其他原因,我终究还是再次来到这篇文章,在进一步的阅读复现中,依旧是发现了部分本人暂时无法理解之处,主要在于**召唤行为**中的两个循环。因为如果找不到更优解,这就是死循环。但是如果将其改成判断,效果又无法达到论文中的所描述的那样。 117 | >当然,在其他人的复现中,大部分是不再将狼群划分为猛狼,探狼等,而是按照粒子群优化方法,所有阶段的所有狼都参与搜寻。 118 | >但是这样仿佛也是一个取巧的过程,因为这就相当于变相的给狼增加搜索次数,如果迭代内部有三个阶段,相当于搜索次数是最大迭代次数的3倍,而倘若在阶段内部又设置了移动策略,那就又要翻倍。总觉得这种方式不太恰当。 119 | >以上仅是个人观点,仅供参考!如有不当,还请见谅。 120 | 121 | ## 4 参考文献 122 | 123 | [1]吴虎胜, 张凤鸣, 吴庐山. 一种新的群体智能算法——狼群算法[J]. 系统工程与电子技术, 2013, 35(11):9. 124 | -------------------------------------------------------------------------------- /粒子群优化算法/一种新的基于Sigmoid函数的自适应加权粒子群优化器/code/python/AWPSO.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2022/7/11 10:56 4 | # @Author : doFighter 5 | import numpy as np 6 | 7 | 8 | def AWPSO(N, dim, x_min, x_max, iterate_max, fitness): 9 | """ 10 | OPSO算法:带有惯性权重的粒子群优化算法,惯性权重随迭代次数线性递减 11 | :param N: 粒子数目 12 | :param dim: 问题维度 13 | :param x_min: 搜索空间下限 14 | :param x_max: 搜索空间上限 15 | :param iterate_max: 最大迭代次数 16 | :param fitness: 评价函数 17 | :return: 返回当前搜索到的最佳适应值 18 | """ 19 | 20 | # 计算求解区间 21 | m = x_max - x_min 22 | v_max = x_max * 0.2 23 | v_min = x_min * 0.2 24 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 25 | v = v_min + (v_max - v_min) * np.random.random([N, dim]) 26 | pBest = x 27 | # 获取初始时全局最优位置 28 | gBest = pBest[0, :] 29 | for i in range(1, N): 30 | if fitness(gBest) > fitness(pBest[i, :]): 31 | gBest = pBest[i, :] 32 | pBest_res = np.ones([N]) 33 | iterate = 0 34 | while iterate < iterate_max: 35 | omega = 0.9 - 0.5 * (iterate / iterate_max) 36 | # 按照笔记中第一种方式计算距离 37 | g_pi = np.sum(abs(pBest - x), axis=1) 38 | g_gi = np.sum(abs(gBest - x), axis=1) 39 | # 按照第二种方式计算距离 40 | # g_pi = np.sum(pBest - x, axis=1) / dim 41 | # g_gi = np.sum(gBest - x, axis=1) / dim 42 | c_g_pi = Sigmoid(g_pi, m) 43 | c_g_gi = Sigmoid(g_gi, m) 44 | # 普通数组转换为numpy数组 45 | c_g_pi = np.expand_dims(np.array(c_g_pi), axis=0).T 46 | c_g_gi = np.expand_dims(np.array(c_g_gi), axis=0).T 47 | v = omega * v + c_g_pi * np.random.random([N, dim]) * (pBest - x) + c_g_gi * np.random.random([N, dim]) * (gBest - x) 48 | # 对速度或位置超出规定的做相应的纠正 49 | v[v > v_max] = v_max 50 | v[v < v_min] = v_min 51 | x = x + v 52 | x[x > x_max] = x_max 53 | x[x < x_min] = x_min 54 | # 更新各粒子的历史最优位置 55 | for i in range(N): 56 | if fitness(pBest[i, :]) > fitness(x[i, :]): 57 | pBest[i, :] = x[i, :] 58 | pBest_res[i] = fitness(pBest[i, :]) 59 | # 更新全局最优位置 60 | if pBest_res.min() < fitness(gBest): 61 | index = np.where(pBest_res == pBest_res.min()) 62 | gBest = pBest[index[0][0], :] 63 | 64 | iterate += 1 65 | res = fitness(gBest) 66 | return res 67 | 68 | 69 | def Sigmoid(D, m): 70 | """ 71 | Sigmoid:加速系数调整函数 72 | :param D: 各维度距离,可直接传入矩阵 73 | :param m: 求解区间 74 | :return: 75 | res:最终的计算结果,数据形状与D一致 76 | """ 77 | # 初始化参数 78 | a = 0.000035 * m 79 | b = 0.5 80 | c = 0 81 | d = 1.5 82 | # 执行 sigmoid 函数 83 | res = b / (1 + np.e ** (-a * (D - c))) + d 84 | return res 85 | -------------------------------------------------------------------------------- /粒子群优化算法/一种新的基于Sigmoid函数的自适应加权粒子群优化器/images/AWPSO-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/一种新的基于Sigmoid函数的自适应加权粒子群优化器/images/AWPSO-1.png -------------------------------------------------------------------------------- /粒子群优化算法/一种新的基于Sigmoid函数的自适应加权粒子群优化器/一种基于Sigmoid函数的自适应加权粒子群优化器.md: -------------------------------------------------------------------------------- 1 | # 一种基于 Sigmoid 函数的自适应加权粒子群优化器(AWPSO) 2 | 3 | ## 1 引言 4 | 5 | 在该文中,提出了一种新的基于`Sigmoid`函数的自适应加权粒子群优化 (PSO) 算法。 6 | 7 | - 算法主要创新:开发了一种基于 sigmoid 函数的加权策略来自适应地调整加速度系数。 8 | 9 | >新提出的自适应加权策略同时考虑了粒子到全局最佳位置的距离和粒子到其个人最佳位置的距离,从而具有提高收敛速度的显着特点。受神经网络激活函数的启发,采用新策略通过 sigmoid 函数更新加速系数。 10 | 11 | 论文DOI:`10.1109/TCYB.2019.2925015` 12 | 13 | ## 2 算法介绍 14 | 15 | ### 2.1 改进起源 16 | 17 | 在`PSO`算法中,加速度系数被用来激励粒子移动到`pbest`和`gbest`。每个粒子的位置到它的`pbest`和`gbest`的距离在确定粒子的运动时起决定性作用。另一方面,控制参数的适应是寻求具有令人信服的效率和准确性的最佳解决方案的重要因素。因此,为了有效地控制`PSO`算法,在论文中,作者努力提出一种新的自适应加权机制,随着迭代的进行,加速度系数可以自适应地调整。 18 | 19 | ### 2.2 权重自适应策略 20 | 21 | 在经典的`PSO`算法中,单个粒子的速度会根据粒子到其`pbest`和`gbest`的距离而加速。因此,选择合适的加速度系数对于通过问题空间找到全局最优解至关重要。在这种情况下,根据上述距离自适应地更新加速系数迭代,以有效提高 PSO 算法的搜索能力,具有理论和实践意义。 22 | 23 | 在文中,作者提到,在很多的`PSO`变体仅以实时迭代次数的方式调整加速度系数(例如公式(1)所示),而没有考虑种群演化的信息。 24 | 25 | $$ 26 | \omega=\omega_{max}-\frac{iterate}{iterate_{max}}\omega_{min}\tag{1} 27 | $$ 28 | 29 | 作者提出,在进化过程的早期,鼓励所有个体尽可能多地探索整个搜索空间。然后,在优化过程的后期,个体被激励收敛到全局最优并尽快找到优化解决方案。从经典粒子速度更新公式中可以看出,粒子更新的速度取决于粒子到它们自己的`pbest`和`gbest`的距离。在这种情况下,根据每个粒子到其`pbest`和`gbest`的距离来调整加速度系数是合理的。 30 | 31 | 考虑到所有上述问题,作者提出了一种自适应加权策略来自适应地控制加速度系数。 32 | 33 | - 主要作用:加快粒子搜索以尽可能快地找到最优解,从而提高收敛速度。 34 | 35 | - 区别:与实时更新策略不同,加速度系数根据粒子与其`gbest`和`pbest`的距离而改变。如果粒子远离其`pbest`和`gbest`,则使用相对较大的加速系数来加速粒子。 36 | 37 | 同时,加速度系数的值被限制在一个适当的范围内,以避免过早收敛,这意味着速度应该是有界的,以保证算法的搜索能力。受前面讨论的启发,作者认为自适应加权更新函数适合描述加速度系数和距离(从粒子到它的`pbest`和`gbest`)之间的关系。换句话说,前一个加速度系数的更新应该适应后一个距离,从而充分证明粒子运动的速度朝向全局最优。从数学的角度来看,所提出的自适应加权更新规则可以描述如下: 38 | 39 | $$ 40 | \begin{cases} 41 | c_{g_{pi}}(k)=F(g_{pi}(k))\\ 42 | c_{g_{gi}}(k)=F(g_{gi}(k)) 43 | \end{cases}\tag{2} 44 | $$ 45 | 46 | >其中,函数$F(·)$表示自适应加权更新函数,后面将会介绍;$g_{pi}(k)$和$g_{gi}(k)$定义为: 47 | $$ 48 | \begin{cases} 49 | g_{pi}(k)=p_i(k)-x_i(k)\\ 50 | g_{gi}(k)=g_i(k)-x_i(k) 51 | \end{cases}\tag{3} 52 | $$ 53 | >分别表示第$k$次迭代时粒子$i$到其$pbest$和$gbest$的距离。 54 | 55 | ### 2.3 自适应加权更新函数的选择 56 | 57 | 直观地说,自适应加权更新函数应该具有以下两个性质: 58 | 1) 更新函数是单调递增的; 59 | 2) 更新函数是有界的。 60 | 61 | 第一个属性主要是由于加速度系数的特性。众所周知,加速度系数是将粒子拉到`pbest`和`gbest`的加权项。远离其`pbest`和`gbest`的粒子需要快速移动到其`pbest`和`gbest`。因此,需要一个单调递增的函数。 62 | 63 | 第二个属性是由约束优化问题的搜索空间是正常有界的事实证明的。一旦一个粒子接近它的`pbest`和`gbest`,运动应该放慢,以避免错过它的`pbest`和`gbest`。因此,加速度系数应该有界以控制粒子的速度。 64 | 65 | 在寻找既单调递增又统一有界的适当更新函数时,神经网络中使用的激活函数似乎是理想的候选者。神经网络有一些流行的激活函数,例如阶跃函数和`sigmoid`函数,其中我们决定选择`sigmoid`函数作为自适应加权更新函数,原因有以下三个: 66 | 1) `sigmoid`函数是单调且有界的; 67 | 2) `sigmoid`函数的曲线是S形的,这样可以避免控制参数发生不希望的突变; 68 | 3) `sigmoid`函数是平滑可微的,从而反映了权重更新迭代的自适应/动态特性。 69 | 70 | 因此,该文采用`sigmoid`函数来调整加速度系数,如公式(4)所示。 71 | 72 | $$ 73 | F(D)=\frac{b}{1+e^{-a(D-c)}}+d\tag{4} 74 | $$ 75 | 76 | >其中`e`是自然对数,`a`表示曲线的陡度,是一个常数值,`b`表示曲线的峰值,`c`表示曲线中心点的横坐标值,`d`是一个正常数值, `D`是由(3)确定的函数的输入。具体来说,`D`是粒子与其认知加速系数的`pbest`之间的距离。对于社会加速度系数,`D`表示粒子与`gbest`之间的距离。 77 | 78 | 在上面的描述中,例如`b`表示的不是公式(4)的峰值,公式(4)的峰值为`b+d`。但是总的来说,这并不会影响我们对论文的理解和复现。 79 | 80 | 总之,所提出的基于 sigmoid 函数的自适应加权策略的三个主要优点总结如下。 81 | 1) 加速度系数自适应控制在合理范围内,自适应加权策略保证了速度更新过程的效率。 82 | 2) 自适应加权更新函数,选择sigmoid函数,用于反映加速度系数的单调但相对平滑的变化,其中较大的距离将导致较大的加速度系数值。 83 | 3) 激发粒子尽可能快地寻求最优解,从而提高准确性和收敛性。 84 | 85 | ### 2.4 AWPSO 算法的框架 86 | 87 | 在该文中,速度及位置更新方式如下(5),(6)式所示。 88 | 89 | $$ 90 | v_i(k+1)=\omega v_i(k)+r_1 c_{g_{pi}}(k) g_{pi}(k)+r_2 c_{g_{gi}}(k) g_{gi}(k)\tag{5} 91 | $$ 92 | 93 | $$ 94 | x_i(k+1)=x_i(k)+v_i(k+1)\tag{6} 95 | $$ 96 | 97 | >其中$\omega$是惯性权重;$g_{pi}(k)$和$g_{gi}(k)$分别表示第$k$次迭代时粒子$i$到其$pbest$和$gbest$的距离;$c_{g_{pi}}(k)$表示由$g_{pi}(k)$确定的加速度常数;$c_{g_{gi}}(k)$表示由$g_{gi}(k)$确定的加速度常数。 98 | >其中需要稍微指出的是,$r_1,r_2$是随机数。 99 | 100 | 流程图如下所示: 101 | 102 | ![ref](images/AWPSO-1.png) 103 | 104 | ## 3 参数设置 105 | 106 | 在原文中,参数设置分别如下: 107 | 108 | - `a=0.000035m` 109 | - `b=0.5` 110 | - `c=0` 111 | - `d=1.5` 112 | 113 | >其中`m`表示优化问题的搜索范围。 114 | 115 | ## 4 代码复现 116 | 117 | 在该文中,对于距离的计算并没有较为清晰的说明。首先我们通过分析文中的描述以及资料可知,加速系数$c_1,c_2$是一个常数,因此距离计算变成了此时最重要的问题,由于文中并未描述因此在实现时,我对以下计算公式进行计算。 118 | 119 | >在原论文的“`IV Experimental Results and Discussion`"章节中,指出了该文使用的是欧氏距离,非常感谢`KoiLiu`的指正。 120 | 121 | $$ 122 | \begin{cases} 123 | g_{pi}(k)=\sum_{d=1}^{dim} |p_i^d(k)-x_i^d(k)|\\ 124 | g_{gi}(k)=\sum_{d=1}^{dim} |g_i^d(k)-x_i^d(k)| 125 | \end{cases}\tag{7} 126 | $$ 127 | 128 | $$ 129 | \begin{cases} 130 | g_{pi}(k)=\frac{1}{dim}\sum_{d=1}^{dim} |p_i^d(k)-x_i^d(k)|\\ 131 | g_{gi}(k)=\frac{1}{dim}\sum_{d=1}^{dim} |g_i^d(k)-x_i^d(k)| 132 | \end{cases}\tag{8} 133 | $$ 134 | 135 | $$ 136 | \begin{cases} 137 | g_{pi}(k)=\sqrt{\sum_{d=1}^{dim} (p_i^d(k)-x_i^d(k))^2}\\ 138 | g_{gi}(k)=\sqrt{\sum_{d=1}^{dim} (g_i^d(k)-x_i^d(k))^2} 139 | \end{cases}\tag{9} 140 | $$ 141 | 142 | >上面三个公式中$dim$代表问题的求解维度。 143 | 144 | 公式(7)和公式(9)可以看成是同一个计算方法,因此我们只需要验证公式(7)和公式(8)。 145 | 146 | 但是从根本上说,距离计算起始应该是公式(9)中描述的,这也是我们常用的,因此在这里我还是倾向于公式(9)的距离计算方法,当然,上面已经说了,公式(9)可以化简为公式(7)的模样,因此为了方便代码编写,可以直接使用公式(7)。 147 | 148 | 149 | ## 5 参考文献 150 | 151 | [1]W. Liu, Z. Wang, Y. Yuan, N. Zeng, K. Hone and X. Liu, "A Novel Sigmoid-Function-Based Adaptive Weighted Particle Swarm Optimizer," in IEEE Transactions on Cybernetics, vol. 51, no. 2, pp. 1085-1093, Feb. 2021, doi: 10.1109/TCYB.2019.2925015. 152 | -------------------------------------------------------------------------------- /粒子群优化算法/一种新的异构改进动态多群粒子群算法/一种新的异构改进动态多群粒子群算法.md: -------------------------------------------------------------------------------- 1 | # 一种新的异构改进动态多群粒子群算法(HIDMS-PSO) 2 | 3 | ## 1 引言 4 | 5 | ## 5 参考文献 6 | 7 | [1]F. T. Varna and P. Husbands, "HIDMS-PSO: A New Heterogeneous Improved Dynamic Multi-Swarm PSO Algorithm," 2020 IEEE Symposium Series on Computational Intelligence (SSCI), 2020, pp. 473-480, doi: 10.1109/SSCI47803.2020.9308313. -------------------------------------------------------------------------------- /粒子群优化算法/双中心粒子群优化/code/matlab/FunDCPSO.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 双中心粒子群优化 3 | % coding:陈小斌 4 | % Github:doFighter 5 | % Encoding format:utf-8 6 | % N: 种群大小 7 | % dim:求解问题的维度 8 | % x_max:解空间上限 9 | % x_min:解空间下限 10 | % iterate_max:最大迭代次数 11 | % fitness:评价函数 12 | %% --------------------------------------------------------------------%% 13 | function [rest] = FunDCPSO(N,dim,x_max,x_min,iterate_max,fitness) 14 | c = 2*ones(1,2); % 定义加速系数 c1,c2;这里直接放入一个矩阵中 15 | v_min = x_min*0.2; 16 | v_max = x_max*0.2; 17 | x = x_min + (x_max-x_min)*rand(N,dim); % 初始化种群位置;三行两列的矩阵,元素处于-10~10之间。三行寓意为种群,两列为维度. 18 | v = v_min + (v_max-v_min)*rand(N,dim); % 初始化种群速度;速度一般在位置的取值范围的10%~20%,这里取10% 19 | pBest = x; % 存储粒子的局部最优值,初始为 初始值 20 | gBest = x(1,:); % 存储粒子的全局最优值 21 | for i = 2:N 22 | if fitness(gBest) > fitness(pBest(i,:)) 23 | gBest = pBest(i,:); 24 | end 25 | end 26 | iterate = 1; 27 | res = inf*ones(N,1); 28 | while iterate < iterate_max+1 29 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 -10~10 时,将其也置为边界数 30 | omega = 0.95 - 0.65*((iterate-1)/iterate_max); 31 | % 更新各粒子的历史最优位置 32 | v1 = omega * v; 33 | x1 = x + v1; 34 | x1(x1 > x_max) = x_max; 35 | x1(x1 < x_min) = x_min; 36 | for i=1:N 37 | if fitness(pBest(i, :)) > fitness(x1(i, :)) 38 | pBest(i, :) = x1(i, :); 39 | end 40 | end 41 | v2 = c(1) * rand(N,dim) .* (pBest - x); 42 | x1 = x1 + v2; 43 | x1(x1 > x_max) = x_max; 44 | x1(x1 < x_min) = x_min; 45 | for i=1:N 46 | if fitness(pBest(i, :)) > fitness(x1(i, :)) 47 | pBest(i, :) = x1(i, :); 48 | end 49 | end 50 | v3 = c(2) * rand(N,dim) .* (gBest - x); 51 | x1 = x1 + v3; 52 | x1(x1 > x_max) = x_max; 53 | x1(x1 < x_min) = x_min; 54 | for i=1:N 55 | if fitness(pBest(i, :)) > fitness(x1(i, :)) 56 | pBest(i, :) = x1(i, :); 57 | end 58 | res(i) = fitness(pBest(i, :)); 59 | end 60 | v = v1 + v2 + v3; 61 | v(v > v_max) = v_max; 62 | v(v < v_min) = v_min; 63 | x = x + v; 64 | x(x > x_max) = x_max; 65 | x(x < x_min) = x_min; 66 | % 更新全局最优位置 67 | x_GCP = 0; 68 | x_SCP = 0; 69 | for i=1:N-2 70 | x_GCP = x_GCP + pBest(i, :); 71 | x_SCP = x_SCP + x(i, :); 72 | end 73 | x_GCP = x_GCP / (N - 2); 74 | x_SCP = x_SCP / (N - 2); 75 | 76 | if min(res) < fitness(gBest) 77 | index = find(res == min(res)); 78 | gBest = pBest(index(1), :); 79 | end 80 | if fitness(x_SCP) < fitness(gBest) 81 | gBest = x_SCP; 82 | end 83 | if fitness(x_GCP) < fitness(gBest) 84 | gBest = x_GCP; 85 | end 86 | 87 | % 迭代计数器加1 88 | iterate = iterate + 1; 89 | end 90 | rest = fitness(gBest); 91 | end 92 | 93 | -------------------------------------------------------------------------------- /粒子群优化算法/双中心粒子群优化/code/python/DCPSO.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2021/8/18 9:15 4 | # @Author : doFighter 5 | 6 | import numpy as np 7 | 8 | 9 | def DCPSO(N, dim, x_min, x_max, iterate_max, fitness): 10 | """ 11 | DCPSO算法:双中心粒子群优化 12 | :param N: 粒子数目 13 | :param dim: 问题维度 14 | :param x_min: 搜索空间下限 15 | :param x_max: 搜索空间上限 16 | :param iterate_max: 最大迭代次数 17 | :param fitness: 评价函数 18 | :return: 返回当前搜索到的最佳适应值 19 | """ 20 | c1 = 2 21 | c2 = 2 22 | v_max = x_max * 0.2 23 | v_min = x_min * 0.2 24 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 25 | v = v_min + (v_max - v_min) * np.random.random([N, dim]) 26 | pBest = x 27 | # 获取初始时全局最优位置 28 | gBest = pBest[0, :] 29 | for i in range(1, N): 30 | if fitness(gBest) > fitness(pBest[i, :]): 31 | gBest = pBest[i, :] 32 | pBest_res = np.ones([N]) 33 | iterate = 0 34 | while iterate < iterate_max: 35 | omega = 0.9 - 0.5 * (iterate / iterate_max) 36 | # 更新各粒子的历史最优位置 37 | v1 = omega * v 38 | x1 = x + v1 39 | x1[x1 > x_max] = x_max 40 | x1[x1 < x_min] = x_min 41 | for i in range(N): 42 | if fitness(pBest[i, :]) > fitness(x1[i, :]): 43 | pBest[i, :] = x1[i, :] 44 | v2 = c1 * np.random.random([N, dim]) * (pBest - x) 45 | x1 = x1 + v2 46 | x1[x1 > x_max] = x_max 47 | x1[x1 < x_min] = x_min 48 | for i in range(N): 49 | if fitness(pBest[i, :]) > fitness(x1[i, :]): 50 | pBest[i, :] = x1[i, :] 51 | v3 = c2 * np.random.random([N, dim]) * (gBest - x) 52 | x1 = x1 + v3 53 | x1[x1 > x_max] = x_max 54 | x1[x1 < x_min] = x_min 55 | for i in range(N): 56 | if fitness(pBest[i, :]) > fitness(x1[i, :]): 57 | pBest[i, :] = x1[i, :] 58 | pBest_res[i] = fitness(pBest[i, :]) 59 | v = v1 + v2 + v3 60 | v[v > v_max] = v_max 61 | v[v < v_min] = v_min 62 | x = x + v 63 | x[x > x_max] = x_max 64 | x[x < x_min] = x_min 65 | # 更新全局最优位置 66 | x_GCP = 0 67 | x_SCP = 0 68 | for i in range(N - 2): 69 | x_GCP += pBest[i, :] 70 | x_SCP += x[i, :] 71 | x_GCP /= (N - 2) 72 | x_SCP /= (N - 2) 73 | 74 | if pBest_res.min() < fitness(gBest): 75 | index = np.where(pBest_res == pBest_res.min()) 76 | gBest = pBest[index[0][0], :].copy() 77 | if fitness(x_SCP) < fitness(gBest): 78 | gBest = x_SCP.copy() 79 | if fitness(x_GCP) < fitness(gBest): 80 | gBest = x_GCP.copy() 81 | iterate += 1 82 | res = fitness(gBest) 83 | return res 84 | 85 | 86 | def Sphere(xx): 87 | """ 88 | Sphere Function 89 | :param xx: 疑似最优解 90 | :return:适应度值 91 | """ 92 | d = len(xx) 93 | sum = 0 94 | for i in range(d): 95 | sum += xx[i] ** 2 96 | return sum 97 | 98 | 99 | def Levy(xx): 100 | d = len(xx) 101 | w = np.zeros(d) 102 | for ii in range(d): 103 | w[ii] = 1 + (xx[ii] - 1) / 4 104 | 105 | term1 = (np.sin(np.pi * w[1])) ** 2 106 | term3 = (w[d - 1] - 1) ** 2 * (1 + (np.sin(2 * np.pi * w[d - 1])) ** 2) 107 | 108 | sum1 = 0 109 | for ii in range(d - 1): 110 | wi = w[ii] 111 | new = (wi - 1) ** 2 * (1 + 10 * (np.sin(np.pi * wi + 1)) ** 2) 112 | sum1 = sum1 + new 113 | 114 | y = term1 + sum1 + term3 115 | return y 116 | 117 | 118 | # 函数测试 119 | for i in range(10): 120 | result = DCPSO(20, 30, -10, 10, 1000, Sphere) 121 | print(result) 122 | -------------------------------------------------------------------------------- /粒子群优化算法/双中心粒子群优化/images/DCPSO-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/双中心粒子群优化/images/DCPSO-1.jpg -------------------------------------------------------------------------------- /粒子群优化算法/双中心粒子群优化/双中心粒子群优化.md: -------------------------------------------------------------------------------- 1 | # 双中心粒子群优化 2 | 3 | ## 1 引言 4 | 5 | 粒子群优化($PSO$)算法是一种新兴的群体智能优化技术,由于其原理简单、参数少、效果好等 优点已经广泛应用于求解各类复杂优化问题.而影响该算法收敛速度和精度的2个主要因素是粒子个 体极值与全局极值的更新方式.通过分析粒子的飞行轨迹和引入广义中心粒子和狭义中心粒子,提出 双中心粒子群优化($double\; center\; particle\; swarm\; optimization,DCPSO$)算法,在不增加算法复杂度条 件下对粒子的个体极值和全局极值更新方式进行更新,从而改善了算法的收敛速度和精度。 6 | 7 | 在双中心粒子群优化中,主要有以下改变: 8 | 9 | 1. 改变轨迹探索方式 10 | 2. 引入广义中心粒子 11 | 3. 引入狭义中心粒子 12 | 13 | ## 2 算法精讲 14 | 15 | 首先需要明确的是,该算法基本沿用 $A\; Modified\; Particle\; Swarm\; Optimizer$(这里称之为 $OPSO$)中的算法结构,在该结构的基础上进行了三点改变: 16 | 17 | - 飞行轨迹搜索改变 18 | - 广义中心粒子 19 | - 狭义中心粒子 20 | 21 | 因此,只要理解更改的部分便能理解该算法。而这三点改变分别体现在两处,分别是: 22 | 23 | - 个体最优位置更新 24 | - 全局最优位置更新 25 | 26 | ### 2.1 个体最优位置更新 27 | 28 | 在 $OPSO$ 中,粒子的更新方式为: 29 | 30 | $$ 31 | v_i^d=\omega v_i^d+c1\times rand_i^d\times (pBest_i^d-x_i^d)+c2\times rand_i^d\times (gBest^d-x_i^d) \tag{1} 32 | $$ 33 | 34 | 因此,最终位置是通过上面的三项进行合成得到。在双中心粒子群优化中,个体最优位置更新是将上面三项进行拆分,在矢量合成的过程中,会经过三个位置,分别为: 35 | 36 | $$ 37 | x_1 = x + \omega v_i^d\\ 38 | x_2 = x_1 + c1\times rand_i^d\times (pBest_i^d-x_i^d)\\ 39 | x_3 = x_2 + c2\times rand_i^d\times (gBest^d-x_i^d)\\ 40 | $$ 41 | 42 | 如下图所示: 43 | 44 | ![ref](images/DCPSO-1.jpg) 45 | 46 | 在上图中粒子飞行路径为 $x_{old}\Rightarrow A\Rightarrow B\Rightarrow x_{new}$,就单个粒子而言,折线运动经历的区域比直线方式复 杂,其捕食范围能够被最大程度地覆盖在整个搜索 空间内,体现在$PSO$算法中,每个粒子能够在更为 广阔的搜索空间内寻找最优解,这样粒子的个体极 值就能够得到显著的改善;从粒子群整体来说,每个粒子个体极值的改善将直接影响着种群全局极值的增强,这一影响使得种群能更快地收敛于最优解. 47 | 48 | 因此在更新时分别会对这三个位置进行比较更新,更新公式如下: 49 | 50 | $$ 51 | f(pBest_i^{new})=min(f(A),f(B),f(x_i^{new},f(pBest_i^{old})))\tag{2} 52 | $$ 53 | 54 | >注意事项:在个体最优位置更新时需要注意,在更新规则方面论文没有详细描述,通过有限测试,在这几个阶段速度不进行约束,但是位置需要约束,不能超过边界。并且最后要对速度进行归正,即执行公式(1),并且需要对最后的位置进行约束。该方式效果会更好! 55 | 56 | - 探讨 57 | 58 | 其实如果深究,就会发现如果在算法中对速度进行约束,那么肯定就无法得到理想中的三个位置,因为在 $OPSO$ 中更新是整体更新,当速度超出范围就会被限制,但是我们无法知道在哪一处被限制。当然,倘若只对位置进行约束,那的确是不会出现上述现象。但是在参考论文中,速度是有限制的。因此我们无法获得准确的轨迹位置,而是依据上面的思想进行编写! 59 | 60 | ### 2.2 全局最优位置更新 61 | 62 | 在全局位置更新中,双中心粒子群优化引入了广义中心粒子($general center particle,GCP$)及狭义中心粒子($special center particle,SCP$),两者计算公式为: 63 | 64 | $$ 65 | x_d^{GCP}=\frac{1}{n-2}(\sum_{i=1}^{n-2}pBest_{id})\tag{3} 66 | $$ 67 | $$ 68 | x_d^{SCP}=\frac{1}{n-2}(\sum_{i=1}^{n-2}x_{id})\tag{3} 69 | $$ 70 | 71 | 最终全局最优位置更新从所有的历史最优位置以及广义中心粒子、狭义中心粒子中竞选,公式如(4)式: 72 | 73 | $$ 74 | f(gBest)=min(f(pBest_1),f(pBest_2),...,f(pBest_N),f(x^{GCP},f(x^{SCP})))\tag{4} 75 | $$ 76 | 77 | ## 3 代码编写 78 | 79 | 代码详见 $code$ 文件夹! 80 | 81 | ## 4 参考文献 82 | 83 | [1].汤可宗,柳炳祥,杨静宇,孙廷凯.双中心粒子群优化算法[J].计算机研究与发展,2012,49(05):1086-1094. 84 | -------------------------------------------------------------------------------- /粒子群优化算法/完全受扰粒子群优化/code/matlab/TDPSO.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 完全受扰粒子群优化:局部版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | % N: 种群大小 6 | % dim:求解问题的维度 7 | % x_max:解空间上限 8 | % x_min:解空间下限 9 | % iterate_max:最大迭代次数 10 | % fitness:评价函数 11 | %% --------------------------------------------------------------------%% 12 | function[result] = TDPSO(N,dim,x_max,x_min,iterate_max,fitness) 13 | % 第一步,生成混沌时间序列 14 | a = 1.4; 15 | b = 0.3; 16 | x = zeros(1,100); 17 | S = zeros(1,100); 18 | x(1) = 0; 19 | S(1) = 0; 20 | for i = 2 : 100 21 | x(i) = S(i-1) + 1 - a*x(i-1)^2; 22 | S(i) = b*x(i-1); 23 | end 24 | % 对混沌时间序列进行归一化操作 25 | S = S - min(S); 26 | S = S / max(S); 27 | % 声明两个学习因子c1,c2,在Parameter optimization of multi-pass turning using chaotic PSO 一文中为2.8,1.3 28 | c = [2.8,1.3]; 29 | % 初始化粒子位置,首先在下面的所用的函数中,粒子的取值范围在[-100,100]之间 30 | x = x_min + (x_max-x_min)*chaos(N,dim,S); 31 | % 初始化粒子速度,每个粒子生成一个随机数,当随机数小于0.5时v取原值,大于等于0.5时取绝对值 32 | v_rand = rand(N,dim); 33 | v = (x_min - chaos(N,dim,S))./(x_max - chaos(N,dim,S)); 34 | v(v_rand>=0.5) = abs(v(v_rand>=0.5)); 35 | 36 | % 声明粒子历史最优解存储数组,初始化为粒子初始位置 37 | pBest = x; 38 | % 声明粒子的全局最优解,并拿到当前初始化的最优位置作为当前全局最优解 39 | res = ones(N,1); 40 | for i=1:N 41 | res(i) = fitness(x(i,:)); 42 | end 43 | position = find(res == min(res)); 44 | gBest = x(position(1),:); 45 | 46 | % 定以起始迭代位置 47 | iterate = 1; 48 | 49 | % 开始迭代 50 | while iterate < iterate_max+1 51 | % 定义惯性权重系数Omega 52 | omega = power(0.5,i) + 0.4; 53 | % 更新粒子群的位置和速度,在原文中根本没有提及是否要对速度以及位置进行限制,而且没有提及最小速度,只提及最大速度 54 | v = omega*v + c(1)*rand(N,dim).*(pBest-x) + c(2)*rand(N,dim).*(gBest-x); 55 | % 保险起见,我们按照PSO原本的约束限制位置 56 | x = x + v; 57 | x(x>x_max) = x_max; 58 | x(x iterate_MAX*0.7 61 | % 查找v_max,v_max定义为所有粒子速度最大的那个值 62 | v_max = max(v); 63 | RVC = v./v_max; 64 | MAX_RVC = (max((RVC')))'; 65 | position = find(MAX_RVC <= 0.5); 66 | cap = size(position); 67 | cap = cap(1); 68 | i = 1; 69 | while i0.5 74 | x(position(i),d(j)) = chaos(1,1,S) + x(position(i),d(j)); 75 | else 76 | x(position(i),d(j)) = chaos(1,1,S) - x(position(i),d(j)); 77 | end 78 | end 79 | i = i + 1; 80 | end 81 | end 82 | % 进行粒子历史最优位置更新以及全局最优位置更新 83 | for i=1:N 84 | if fitness(pBest(i,:))>fitness(x(i,:)) 85 | pBest(i,:) = x(i,:); 86 | end 87 | res(i) = fitness(pBest(i,:)); 88 | end 89 | if fitness(gBest)>min(res) 90 | pos = find(res == min(res)); 91 | gBest = pBest(pos(1),:); 92 | end 93 | iterate = iterate + 1; 94 | end 95 | result = fitness(gBest); 96 | end 97 | 98 | 99 | % 编写 chaos 函数 100 | function[res] = chaos(m,n,S) 101 | res = S(ceil(rand(m,n)*100)); 102 | end -------------------------------------------------------------------------------- /粒子群优化算法/完全受扰粒子群优化/code/python/TDPSO.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2021/8/16 9:24 4 | # @Author : doFighter 5 | import numpy as np 6 | 7 | 8 | def chaos(m, n, S): 9 | """ 10 | 混沌时间序列随机数生成器 11 | :param m: 行数指标 12 | :param n: 列数指标 13 | :param S: 混沌时间序列 14 | :return: 返回生成的随机数组 15 | """ 16 | index = np.ceil(np.random.rand(m, n) * 99).astype(int) 17 | res = S[index] 18 | return res 19 | 20 | 21 | def TDPSO(N, dim, x_min, x_max, iterate_max, fitness): 22 | """ 23 | 完全受扰粒子群优化算法 24 | :param N: 种群数目 25 | :param dim: 问题维度 26 | :param x_min: 解空间下限 27 | :param x_max: 解空间上限 28 | :param iterate_max: 最大迭代次数 29 | :param fitness: 适应度值 30 | :return: 最优适应值 31 | """ 32 | # 第一步,生成混沌时间序列 33 | a = 1.4 34 | b = 0.3 35 | x = np.zeros(100) 36 | S = np.zeros(100) 37 | x[0] = 0 38 | S[0] = 0 39 | for i in range(1, 100): 40 | x[i] = S[i - 1] + 1 - a * x[i - 1] ** 2 41 | S[i] = b * x[i - 1] 42 | # 对混沌时间序列进行归一化操作 43 | S = S - min(S) 44 | S = S / max(S) 45 | 46 | c = [2.8, 1.3] 47 | x = x_min + (x_max - x_min) * chaos(N, dim, S) 48 | v_rand = np.random.rand(N, dim) 49 | v = (x_min - chaos(N, dim, S)) / (x_max - chaos(N, dim, S)) 50 | v[v_rand >= 0.5] = abs(v[v_rand >= 0.5]) 51 | pBest = x 52 | # 获取初始时全局最优位置 53 | gBest = pBest[0, :] 54 | for i in range(1, N): 55 | if fitness(gBest) > fitness(pBest[i, :]): 56 | gBest = pBest[i, :] 57 | iterate = 0 58 | pBest_res = np.ones([N]) 59 | while iterate < iterate_max: 60 | omega = np.power(0.5, iterate + 1) + 0.4 61 | v = omega * v + c[0] * np.random.rand(N, dim) * ( 62 | pBest - x) + c[1] * np.random.rand(N, dim) * (gBest - x) 63 | x += v 64 | x[x > x_max] = x_max 65 | x[x < x_min] = x_min 66 | if iterate > iterate_max * 0.7: 67 | v_max = np.max(v, 0) 68 | # 在python中会出现数字太小,而导致除法运算的警告,因此在本算法中,对绝对值过小的数统一赋值 69 | v_max[(v_max > 0) & (v_max < np.exp(-60))] = np.exp(-60) 70 | v_max[(v_max < 0) & (v_max > -np.exp(-60))] = -np.exp(-60) 71 | # v_max[abs(v_max) < np.exp(-30)] = np.exp(-30) 72 | RVC = v / v_max 73 | MAX_RVC = (np.max(RVC.T, 0)).T 74 | position = np.array(np.where(MAX_RVC <= 0.5))[0] 75 | cap = np.size(position) 76 | for i in range(cap): 77 | d = np.random.choice(30, int(dim * 0.5), replace=False) 78 | for j in range(int(dim * 0.5)): 79 | flag = np.random.rand() 80 | if flag > 0.5: 81 | x[position[i], d[j]] = chaos( 82 | 1, 1, S)[0] + x[position[i], d[j]] 83 | else: 84 | x[position[i], d[j]] = chaos( 85 | 1, 1, S)[0] - x[position[i], d[j]] 86 | # 更新各粒子的历史最优位置 87 | for i in range(N): 88 | if fitness(pBest[i, :]) > fitness(x[i, :]): 89 | pBest[i, :] = x[i, :] 90 | pBest_res[i] = fitness(pBest[i, :]) 91 | # 更新全局最优位置 92 | if pBest_res.min() < fitness(gBest): 93 | index = np.where(pBest_res == pBest_res.min()) 94 | gBest = pBest[index[0][0], :] 95 | iterate += 1 96 | result = fitness(gBest) 97 | return result 98 | 99 | 100 | def Sphere(xx): 101 | """ 102 | Sphere Function 103 | :param xx: 疑似最优解 104 | :return:适应度值 105 | """ 106 | d = len(xx) 107 | sum = 0 108 | for i in range(d): 109 | sum += xx[i] ** 2 110 | return sum 111 | 112 | 113 | # 函数测试 114 | for i in range(10): 115 | result = TDPSO(20, 30, -10, 10, 1000, Sphere) 116 | print(result) 117 | -------------------------------------------------------------------------------- /粒子群优化算法/完全受扰粒子群优化/images/TDPSO-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/完全受扰粒子群优化/images/TDPSO-1.png -------------------------------------------------------------------------------- /粒子群优化算法/完全受扰粒子群优化/images/TDPSO-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/完全受扰粒子群优化/images/TDPSO-2.png -------------------------------------------------------------------------------- /粒子群优化算法/完全受扰粒子群优化/images/TDPSO-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/完全受扰粒子群优化/images/TDPSO-3.png -------------------------------------------------------------------------------- /粒子群优化算法/完全受扰粒子群优化/完全受扰的混沌粒子群优化算法.md: -------------------------------------------------------------------------------- 1 | # 完全受扰的混沌粒子群优化算法 2 | 3 | 本文章以 《**Parameter optimization of multi-pass turning using chaotic PSO**》为基准,描述该文章中描述的完全受扰的混沌粒子群算法。 4 | 5 | ## 1 缘起 6 | 7 | 本文的作者为何会提出该算法,又是如何对粒子群进行改进的,现在就让我们来了解该改进算法的来由。 8 | 该算法提出的目的是为了确定一组最佳加工参数,以生产具有可观质量和最低制造成本的订购产品。 加工模型的非线性和高度约束的性质限制了基于经典梯度的技术处理此类问题的应用。 所以在该文章中的重点是在多道次车削操作中获得最佳加工条件。 9 | >上面描述了提出该改进算法需要解决的问题,倘若你不是机械专业的,或者对多道次车削操作不了解的话,对上面的描述基本是一头雾水。 10 | > 11 | >但是无妨,本文主要是为了介绍算法,不需要对它的当前应用场景太过于熟知。下面才是重点!! 12 | 13 | 为了解决上面的问题,**该文章提出了一种混沌 PSO,即完全受扰粒子群优化 (TDPSO),PSO 的增强变体用于在受到各种约束的多道次车削操作期间获得最佳加工条件。 在 TDPSO 中,混沌现象嵌入在 PSO 的不同阶段,以提高搜索过程的效率。** 将 TDPSO 获得的结果与文献中可用的结果进行比较,可以看出 TDPSO 对处理此类问题非常有效。 14 | 15 | ## 2 算法介绍 16 | 17 | 混沌 PSO 的随机性是由选择各种 PSO 参数所需的随机序列引起的。 在这里,采用混沌系统而不是均匀分布来在搜索过程的不同阶段生成随机序列。 18 | 19 | ### 2.1 混沌系统 20 | 21 | 在开始时引入混沌以生成初始种群。 这与基本 PSO 形成对比,其中初始种群是使用均匀分布的随机数生成的。 其次,为了防止局部优化器上的“粒子停滞”,当算法接近平衡状态时,在以后的迭代中嵌入混沌。 为此,根据“速度指数标准”从群中选择一些粒子进行扰动。 通过这种方式,将混沌嵌入 PSO 以增强全局搜索能力并避免停滞现象。 混沌是使用 Henon 混沌系统产生的,以扰乱搜索过程。 22 | 23 | #### 2.1.1 混沌现象 24 | 25 | **混沌**一词原指宇宙未形成之前的混乱状态,中国及古希腊哲学家对于宇宙之源起即持混沌论,主张宇宙是由混沌之初逐渐形成现今有条不紊的世界。在井然有序的宇宙中,西方自然科学家经过长期的探讨,逐一发现众多自然界中的规律,如大家耳熟能详的地心引力、杠杆原理、相对论等。这些自然规律都能用单一的数学公式加以描述,并可以依据此公式准确预测物体的行径。 26 | 混沌现象起因于物体不断以某种规则复制前一阶段的运动状态,而产生无法预测的随机效果。所谓“差之毫厘,失之千里”正是此一现象的最佳批注。**具体而言,混沌现象发生于易变动的物体或系统,该物体在行动之初极为单纯,但经过一定规则的连续变动之后,却产生始料所未及的后果,也就是混沌状态**。但是此种混沌状态不同于一般杂乱无章的的混乱状况,此一混沌现象经过长期及完整分析之后,可以从中理出某种规则出来。混沌现象虽然最先用于解释自然界,但是在人文及社会领域中因为事物之间相互牵引,混沌现象尤为多见。如股票市场的起伏、人生的平坦曲折、教育的复杂过程。 27 | 28 | >- 混沌系统:简单来讲就是指一种系统呈现出一种杂乱无章且无法预测结果的系统。 29 | 30 | #### 2.1.2 Henon Map 31 | 32 | **Henon Map**(也称 Henon 映射)是一个二维离散时间动力系统,表现出混沌行为。 1976年由法国天文学家米歇尔·海农提出,作为洛伦兹模型的庞加莱图的简化模型。 它是一个耗散二次映射,它将平面中的点 $(x_n, y_n)$ 映射到一个新点,映射规则如下所示: 33 | $$ 34 | \begin{align} 35 | x_{n+1} = y_n+1-ax_n^2\\ 36 | y_{n+1} = bx_n 37 | \end{align} 38 | $$ 39 | 这里以$x_0=0,y_0=0$为起始值,迭代一百次,其对应的y和x值的分布如下所示: 40 | ![ref](images/TDPSO-1.png)![ref](images/TDPSO-2.png) 41 | 42 | 从上图中可以看出x和y都是呈现一种无序的状态,现在关键是用混沌时间序列取代伪随机序列值,所以需要将x或者y值映射到[0,1]范围内。这里使用如下公式进行映射: 43 | $$ 44 | \begin{align} 45 | z=z-min(z)\\ 46 | z=\frac{z}{max(z)} 47 | \end{align} 48 | $$ 49 | >z的取值范围为数组x,y 50 | 51 | 这样就将$z$约束在[0,1]范围内,这里以约束y为例,可得下图的时间序列: 52 | ![ref](images/TDPSO-3.png) 53 | 54 | 如此就将 Henon Map 映射值约束在[0,1]之间,完成了归一化的操作。这就完成了在算法中使用混沌随机数取代 rand 函数产生的伪随机数的第一步。 55 | 56 | #### 2.1.3 chaos函数原理 57 | 58 | 在2.1.2节我们已经拿到了归一化的基于 Henon Map 映射的混沌时间序列,现在就是分析如何编写chaos函数,函数是如何运行的。在原期刊中并未有详细的介绍,以下是基于个人推测: 59 | 60 | - 迭代一百次,拿到完成归一化操作的 Henon Map 混沌时间序列,该序列相当于一个数组,内含有100个基于 Henon Map 映射的元素。 61 | - 在chaos函数中随机生成一个[1-100]范围内的随机整数,以该整数获取对应下标的混沌时间序列。 62 | - 将该下标对应的混沌随机数返回。 63 | 64 | 完成以上操作,其实质和所用的rand函数基本一致。在接下来的操作中,就可以直接调用 chaos 函数。 65 | 66 | ### 2.2 算法核心公式 67 | 68 | 在本小节,只会描述与标准粒子群优化算法所不一样的算法公式,所以没有提及的,则说明和标准粒子群优化算法是一样的。 69 | 70 | #### 2.2.1 位置和速度的初始化 71 | 72 | 混沌粒子群优化算法的位置初始化和原始的标准粒子群优化算法一样,虽然表达公式不一样,但其核心是一样的,只不过该文中使用的是混沌随机数,标准粒子群优化中使用的是rand普通随机数。详见公式(5)。但是其速度更新公式却是有点不一样,不过根据公式来看的话,刚好是在-1和1的附近,详见公式(6)。 73 | $$ 74 | \begin{align} 75 | x_{i,d} = x_{i,min}+(x_{i,max}-x_{i,min})\times chaos()\\ 76 | v_{i,d} = \begin{cases} 77 | \frac{x_{i,min}-chaos()}{x_{i,max}-chaos()} &\text{if rand<0.5}\\ 78 | \vert\frac{x_{i,min}-chaos()}{x_{i,max}-chaos()}\vert &\text{if rand>= 0.5} 79 | \end{cases} 80 | \end{align} 81 | $$ 82 | 83 | #### 2.2.2 扰动指标(Perturbation index) 84 | 85 | 扰动现象首先需要了解扰动指数,也称为每个粒子的“相对速度系数”。 86 | 87 | ##### 2.2.2.1 扰动指数-相对速度系数(Relative velocity coefficient) 88 | 89 | 在该文中,使用 Henon 映射生成初始种群后,评估和更新粒子的过程与标准 PSO 中的过程保持一致。 但是,经过指定次数的迭代后,会为每个维度中的每个粒子计算一个相对速度指数。相对速度指数计算方法如下: 90 | 91 | - 1. 相对速度指标 92 | 首先需要计算相对速度指标,相对速度指标的计算方法为:第$i$个粒子的第$d$维解空间相对速度指标等于该粒子第$d$维的值除以所有粒子第$d$维中的最大值。如下公式(7)所示: 93 | $$ 94 | \begin{align} 95 | RCV_{i,d}=\frac{v_{i,d}}{V_{max,d}} 96 | \end{align} 97 | $$ 98 | - 2. 最大相对速度系数 99 | 通过公式(7)能够得到每个粒子每维的相对速度指标,之后从每个粒子的各维中获取最大的一维的数值,将其作为该粒子的最大相对速度系数。公式如式(8): 100 | $$ 101 | \begin{align} 102 | (Max_RVC)_i=max\{RVC_{i,1},RVC_{i,2},RVC_{i,3},\dotsb,RVC_{i,d} \} 103 | \end{align} 104 | $$ 105 | 计算所得到的最大相对速度系数决定了群中的一个粒子是否应该受到干扰。 选择具有最大相对速度系数在 [0,0.5] 范围内的粒子进行扰动。 Max_RVC 的较小值意味着粒子具有较低的速度,并且很可能被困在局部最优中,表明需要外力将其从这些区域中拉出来。 106 | 107 | #### 2.2.3 粒子扰动(Disturbing particles) 108 | 109 | 粒子扰动是根据最大相对速度系数,选择粒子通过混沌时间序列扰乱其当前状态。 110 | 111 | 在该文中,通过一系列实验表明,并不需要对最大相对粒子速度在[0,0.5]之间的粒子的所有维度都进行扰动,当问题解的维度大于等于10的时候,只需要对其维度空间的一般进行扰动,当问题解的维度小于10的时候,可以对其所有的维度进行扰动。(当然,这只是在该文中的建议,比较不一定刚好以10为界限,但是可能在作者的实验中,当大于10时候进行全维度扰动效果会比较不理想。) 112 | 113 | ##### 2.2.3.1 扰动启动条件 114 | 115 | 对粒子的扰动并不是一开始就进行的,首先要了解目的。扰动的目的是为了使粒子跳出局部最优,所以一般是在粒子陷入局部最优,一直在某个范围内跳动无法进一步搜索的时候进行扰动的。 116 | 117 | 在该文中,作者提出,当迭代进行到70%之后,开始对粒子进行扰动。扰动方法如下: 118 | 119 | 1. 首先选择最大相对速度系数在[0,0.5]之间的粒子。 120 | 2. 对粒子其中的一半的维度进行随机扰动(当维度大于等于10时),扰动方法如公式(9)所示。 121 | $$ 122 | \begin{align} 123 | x_{i,d}(t+1) = chaos()\pm x_{i,d}(t) 124 | \end{align} 125 | $$ 126 | >其中t为迭代次数,chaos() 是一个使用 Henon 映射产生混沌随机数的函数。 127 | 128 | ### 2.3 算法流程及相关变量值 129 | 130 | #### 2.3.1 相关变量取值 131 | 132 | 在该文中,对以下参数进行了设置: 133 | 134 | - 1. 惯性权重 $\omega$:从0.9以指数方式下降至0.4. 135 | - 2. 种群大小:种群大小应为待求解问题空间的五倍(个人认为倘若是需要求解特定问题的最佳方案,可以采取该建议。倘若只是想测算该算法是否具有更好的寻求解能力,那么只需将需要对比的算法种群初始为同样大小) 136 | - 3. 学习因子:学习因子$c_1,c_2$分别设置为2.8和1.3. 137 | - 4. $v_{max,d}$初始时设置为$0.5\times (x_{max}-x_{min})$,其中$x_{max},x_{min}$为解的取值范围的上限和下限。(在python或者matlab这类语言中,无需对其初始化,直接可以后面的运行过程中直接拿到对应维度的最大值,当然倘若是强类型语言,那么就需要在一开始进行声明) 138 | 139 | #### 2.3.2 算法流程 140 | 141 | - Step 1: 初始化相关函数以及参数 142 | - Step 1.1: 通过 Henon 映射得到混沌时间序列,再将该序列归一化,使得取值在[0,1]内,保存到S中。 143 | - Step 1.2: 编写chaos()函数,随机从混沌序列S中取值。 144 | - Step 1.3: 分别按照公式(5)以及公式(6)进行粒子群位置和速度的初始化。 145 | - Step 1.4: 初始化 $pBest_i=x_i$,并通过适应值函数获取最优适应值位置$x_{best}$并将其赋值给$gBest$。 146 | - Step 1.5: 初始化起始迭代次数iterate以及最大迭代次数。 147 | - Step 2: 进入循环,开使循环内的代码 148 | - Step 2.1: 按照标准粒子群优化算法更新粒子速度以及位置。 149 | - Step 2.2: 判断迭代次数是否超过总迭代次数的70%,若超过,则执行下面语句。 150 | - Step 2.2.1: 获取粒子每一维中速度的最大值$v_{max,d}$。 151 | - Step 2.2.2: 通过$v_{max,d}$来求解每个粒子对应维度的相对速度指标,求解公式如(7)所示。 152 | - Step 2.2.3: 通过每个粒子的相对速度指标来求取每个粒子的最大相对速度系数。公式如(8)所示。 153 | - Step 2.2.4: 筛选出最大相对速度系数在[0,0.5]之间的粒子按照下列方式进行扰动。 154 | - Step 2.2.4.1: 选择需要扰动的粒子维度的一半进行扰动,扰动公式如(9)所示,在这里,可生成一个随机数r,当r>0.5时选择执行$x_{i,d}(t+1)=chaos()+x_{i,d}(t)$,否则执行$x_{i,d}(t+1)=chaos()-x_{i,d}(t)$ 155 | - Step 2.3: 对当前的粒子历史最优位置以及全局最优位置进行更新。 156 | - Step 2.4: 迭代次数加一,并判断是否超出最大迭代次数倘若超出,则跳出循环,否则,继续循环。 157 | - Step 3: 执行结束,输出最优解。 158 | 159 | ### 2.4 代码 160 | 161 | 代码在code文件中,命名为 TDPSO,请自行获取。 162 | 163 | ## 参考文献 164 | 165 | [1]Chauhan P, Pant M, Deep K. Parameter optimization of multi-pass turning using chaotic PSO[J]. International Journal of Machine Learning and Cybernetics, 2015, 6(2): 319-337. 166 | -------------------------------------------------------------------------------- /粒子群优化算法/带收缩因子的粒子群优化/code/matlab/FunVPSO.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 带收缩因子的粒子群优化(DOI:10.1109/CEC.2002.1004493) 3 | % coding:陈小斌 4 | % Encoding format:utf-8 5 | % N: 种群大小 6 | % dim:求解问题的维度 7 | % x_max:解空间上限 8 | % x_min:解空间下限 9 | % iterate_max:最大迭代次数 10 | % fitness:评价函数 11 | %% --------------------------------------------------------------------%% 12 | function[rest]=FunVPSO(N,dim,x_max,x_min,iterate_max,fitness) 13 | chi = 0.729844; 14 | varphi = 2.05; 15 | %由于在文中未能看到上面的 rand 是随机生成亦或是初始化生成,这里使用随机生成 16 | v_min = x_min*0.2; 17 | v_max = x_max*0.2; 18 | x = x_min + (x_max-x_min)*rand(N,dim); % 初始化种群位置;三行两列的矩阵,元素处于-10~10之间。三行寓意为种群,两列为维度. 19 | v = v_min + (v_max-v_min)*rand(N,dim); % 初始化种群速度;速度一般在位置的取值范围的10%~20%,这里取10% 20 | pBest = x; % 存储粒子的局部最优值,初始为 初始值 21 | gBest = x(1,:); % 存储粒子的全局最优值 22 | for i = 2:N 23 | if fitness(gBest) > fitness(pBest(i,:)) 24 | gBest = pBest(i,:); 25 | end 26 | end 27 | iterate = 1; 28 | res = inf*ones(N,1); 29 | while iterate < iterate_max+1 30 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 边界 时,将其也置为边界数 31 | v = chi*(v + varphi*rand(N,dim).*(pBest-x) + varphi*rand(N,dim).*(gBest-x)); 32 | v(v>v_max) = v_max; 33 | v(vx_max) = x_max; 36 | x(x fitness(pBest[i, :]): 28 | gBest = pBest[i, :] 29 | pBest_res = np.ones([N]) 30 | iterate = 0 31 | while iterate < iterate_max: 32 | v = chi * (v + varphi * np.random.random([N, dim]) * ( 33 | pBest - x) + varphi * np.random.random([N, dim]) * (gBest - x)) 34 | # 对速度或位置超出规定的做相应的纠正 35 | v[v > v_max] = v_max 36 | v[v < v_min] = v_min 37 | x = x + v 38 | x[x > x_max] = x_max 39 | x[x < x_min] = x_min 40 | # 更新各粒子的历史最优位置 41 | for i in range(N): 42 | if fitness(pBest[i, :]) > fitness(x[i, :]): 43 | pBest[i, :] = x[i, :] 44 | pBest_res[i] = fitness(pBest[i, :]) 45 | # 更新全局最优位置 46 | if pBest_res.min() < fitness(gBest): 47 | index = np.where(pBest_res == pBest_res.min()) 48 | gBest = pBest[index[0][0], :] 49 | 50 | iterate += 1 51 | res = fitness(gBest) 52 | return res 53 | 54 | 55 | def Sphere(xx): 56 | """ 57 | Sphere Function 58 | :param xx: 疑似最优解 59 | :return:适应度值 60 | """ 61 | d = len(xx) 62 | sum = 0 63 | for i in range(d): 64 | sum += xx[i] ** 2 65 | return sum 66 | 67 | 68 | # 函数测试 69 | result = VPSO(20, 30, -10, 10, 1000, Sphere) 70 | print(result) 71 | -------------------------------------------------------------------------------- /粒子群优化算法/带收缩因子的粒子群优化/一种使用收缩因子的粒子群优化算法.md: -------------------------------------------------------------------------------- 1 | # 一种使用收缩因子的粒子群优化算法 2 | 3 | 本文介绍的一种使用收缩因子的粒子群优化算法是基于Eberhart R C发表的一篇名为《**Comparing inertia weights and constriction factors in particle swarm optimization**》论文而写的,在该论文中作者首次提到了该算法,并使用该算法与带有惯性权重的粒子群优化算法进行比较。 4 | 5 | ## 1 摘要 6 | 7 | 在参考文献[1]中Eberhart R C提到了本文所讲的算法,并将使用惯性权重的粒子群优化算法与使用收缩因子的粒子群优化算法进行性能上的比较。通过使用五个基准函数进行比较后得出的结论是,使用收缩因子的粒子群优化算法在性能上要优于使用惯性权重的粒子群优化算法,并且这种方法在基准函数上的性能优于作者已知的任何其他已发表的结果。在之后Kennedy, J. 和 R. Mendes在《**Population structure and particle swarm performance**》再次提及该算法。 8 | 9 | ## 2 算法介绍 10 | 11 | 在文献[1]中作者介绍了一种带有收缩因子的粒子群算法,对于算法的来由却没有细致的讲解,只是说在众多的测试当中得到该方法。在文献[2]中提及这是实现了文献[3]中的第一种类型聚拢的粒子群优化算法。对于文献[3],该文分析了粒子在离散时间运动时的轨迹(代数观点),然后发展到连续时间的观点(分析观点)。开发了一个五维描述,它完整地描述了系统。这些分析导致了算法的广义模型,其中包含一组用于控制系统收敛趋势的系数。粒子群优化器的一些结果,实现了从分析中得出的修改,提出了改变原始算法的方法,以消除问题并提高粒子群找到一些经过充分研究的测试函数的最优值的能力。 12 | 13 | 但是对于本文所讲的粒子群优化算法,或许可以使用一种更为方便理解的方式进行描述。为了便于描述,接下来使用 **VPSO** 代指使用收缩因子的粒子群优化算法,**OPSO** 代指使用惯性权重的粒子群优化算法。 14 | 15 | 首先,该算法对于普通的粒子群优化算法的结构并未有较大的改变,主要变化在于速度的更新,即与在 **[粒子群优化二](粒子群优化二.md)** 中介绍的带惯性权重 $\omega$ 的粒子群优化算法(OPSO)相似。VPSO的速度更新公式如下: 16 | $$ 17 | v_i^d=\chi(v_i^d-c_1*rand*(pBest_i^d-x_i^d)+c_2*rand*(gBest^d-x_i^d))\tag{1} 18 | $$ 19 | 从公式(1)来看,VPSO与OPSO的区别并不大,OPSO速度更新公式如下: 20 | $$ 21 | v_i^d=\omega v_i^d+c_1\times rand_i^d\times (pBest_i^d-x_i^d)+c_2\times rand_i^d\times (gBest^d-x_i^d) \tag{2} 22 | $$ 23 | 说区别不大系数个数并未改变,仅仅是将 $\omega$ 拿到了最外面,并将该未知数的表示换成 $\chi$ ,但这同时又是一个极大的改变,在OPSO中,随着搜索进行而不断减少小的速度增量只有 $v_i^d$ ,而当防止在最外面的时候就完全改变了这种状态,此时是将整体的位移减少,以此达到更加细致的搜索效果。 24 | 25 | 这会带来怎样的效果呢?可以举一个简单的例子! 26 | 公式(2)中的速度更新是通过粒子历史最优以及全局历史最优两者的矢量和叠加得到的,而后再加上上一次速度的 $\omega$ 倍,所以可以看出粒子会以一个极高的速度接近全局最优点。而VPSO则不同,$\chi$ 在更新速度时是作用于全局,以至于粒子在接近全局最优时会减少其步长,如此就能达到更缓慢的逼近全局最优解。 27 | 28 | 在OPSO中 $\omega$ 是随迭代次数的进行在[0.9,0.5]之间线性递减的。而在VPSO中 $\chi$ 是一个定值,大小为:0.729844,而 $\chi$ 与 $c_1,c_2$ 具有如下关系: 29 | $$ 30 | \chi=\frac{2}{\vert 2-\varphi-\sqrt{\varphi^2-4\varphi} \vert};\varphi=c_1+c_2,\varphi>4\tag{3} 31 | $$ 32 | 在文献[1]与文献[2]中皆提到它们的取值,但是有点不一样,在文献[2]中 $c_1,c_2$ 取值是2.01,倘若取该值,则无法得到对应的 $\chi$ 值,所以应该是作者笔误,在VPSO中 $c_1,c_2$ 的取值为 2.05。 33 | 34 | 在文献[1]中作者对速度的设置是和位置取值范围相同的,同时对粒子是否越界不进行判断的,但是其实只要对应算法采用的方式一样,那么通过对比便能得出VPSO确实比其他粒子群优化算法要更为优越。 35 | 36 | ## 3 算法实现 37 | 38 | VPSO实现和其他算法一样,除了速度的更新方式不同,具体代码请见code文件夹,可获取相应语言的完整代码。 39 | 40 | ## 4 参考文献 41 | 42 | [1] Eberhart R C . Comparing inertia weights and constriction factors in particle swarm optimization[C]// Proceedings of the 2000 IEEE Congress on Evolutionary Computation, La Jolla, CA. IEEE, 2002. 43 | [2] Kennedy, J. and R. Mendes (2002). Population structure and particle swarm performance. Proceedings of the Evolutionary Computation on 2002. CEC '02. Proceedings of the 2002 Congress - Volume 02, IEEE Computer Society: 1671–1676. 44 | [3] Clerc M , Kennedy J . The particle swarm - explosion, stability, and convergence in a multidimensional complex space[J]. IEEE Transactions on Evolutionary Computation, 2002, 6(1):58-73. 45 | -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/code/matlab/FunPSO_GBEST.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 粒子群优化:最早版本(doi:10.1109/icnn.1995.488968) 3 | % coding:陈小斌 4 | % Github:doFighter 5 | % Encoding format:utf-8 6 | % N: 种群大小 7 | % dim:求解问题的维度 8 | % x_max:解空间上限 9 | % x_min:解空间下限 10 | % iterate_max:最大迭代次数 11 | % fitness:评价函数 12 | %% --------------------------------------------------------------------%% 13 | function[rest]=FunPSO_GBEST(N,dim,x_max,x_min,iterate_max,fitness) 14 | c = 2*ones(1,2); % 定义加速系数 c1,c2;这里直接放入一个矩阵中 15 | %由于在文中未能看到上面的 rand 是随机生成亦或是初始化生成,这里使用随机生成 16 | v_min = x_min*0.2; 17 | v_max = x_max*0.2; 18 | x = x_min + (x_max-x_min)*rand(N,dim); % 初始化种群位置;三行两列的矩阵,元素处于-10~10之间。三行寓意为种群,两列为维度. 19 | v = v_min + (v_max-v_min)*rand(N,dim); % 初始化种群速度;速度一般在位置的取值范围的10%~20%,这里取10% 20 | pBest = x; % 存储粒子的局部最优值,初始为 初始值 21 | gBest = x(1,:); % 存储粒子的全局最优值 22 | for i = 2:N 23 | if fitness(gBest) > fitness(pBest(i,:)) 24 | gBest = pBest(i,:); 25 | end 26 | end 27 | iterate = 1; 28 | res = inf*ones(N,1); 29 | while iterate < iterate_max+2 30 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 边界 时,将其也置为边界数 31 | v = v + c(1)*rand(N,dim).*(pBest-x) + c(2)*rand(N,dim).*(gBest-x); 32 | v(v>v_max) = v_max; 33 | v(vx_max) = x_max; 36 | x(x N 42 | nex = 1; 43 | end 44 | v(i,:) = v(i,:) + c(1)*rand(1,dim).*(pBest(i,:)-x(i,:)) + c(2)*rand(1,dim).*(pBest(pre,:)-x(i,:)) + c(3)*rand(1,dim).*(pBest(nex,:)-x(i,:)); 45 | end 46 | v(v>v_max) = v_max; 47 | v(vx_max) = x_max; 50 | x(x fitness(pBest(i,:)) 23 | gBest = pBest(i,:); 24 | end 25 | end 26 | iterate = 1; 27 | res = inf*ones(N,1); 28 | while iterate < iterate_max+1 29 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 -10~10 时,将其也置为边界数 30 | omega = 0.9 - 0.5*((iterate-1)/iterate_max); 31 | v = omega*v + c(1)*rand(N,dim).*(pBest-x) + c(2)*rand(N,dim).*(gBest-x); 32 | v(v>v_max) = v_max; 33 | v(vx_max) = x_max; 36 | x(x fitness(pBest[i, :]): 28 | gBest = pBest[i, :] 29 | pBest_res = np.ones([N]) 30 | iterate = 0 31 | while iterate < iterate_max: 32 | omega = 0.9 - 0.5 * (iterate / iterate_max) 33 | v = omega * v + c1 * \ 34 | np.random.random([N, dim]) * (pBest - x) + c2 * \ 35 | np.random.random([N, dim]) * (gBest - x) 36 | # 对速度或位置超出规定的做相应的纠正 37 | v[v > v_max] = v_max 38 | v[v < v_min] = v_min 39 | x = x + v 40 | x[x > x_max] = x_max 41 | x[x < x_min] = x_min 42 | # 更新各粒子的历史最优位置 43 | for i in range(N): 44 | if fitness(pBest[i, :]) > fitness(x[i, :]): 45 | pBest[i, :] = x[i, :] 46 | pBest_res[i] = fitness(pBest[i, :]) 47 | # 更新全局最优位置 48 | if pBest_res.min() < fitness(gBest): 49 | index = np.where(pBest_res == pBest_res.min()) 50 | gBest = pBest[index[0][0], :] 51 | 52 | iterate += 1 53 | res = fitness(gBest) 54 | return res 55 | 56 | 57 | def Sphere(xx): 58 | """ 59 | Sphere Function 60 | :param xx: 疑似最优解 61 | :return:适应度值 62 | """ 63 | d = len(xx) 64 | sum = 0 65 | for i in range(d): 66 | sum += xx[i] ** 2 67 | return sum 68 | 69 | 70 | def Levy(xx): 71 | d = len(xx) 72 | w = np.zeros(d) 73 | for ii in range(d): 74 | w[ii] = 1 + (xx[ii] - 1) / 4 75 | 76 | term1 = (np.sin(np.pi * w[1])) ** 2 77 | term3 = (w[d - 1] - 1) ** 2 * (1 + (np.sin(2 * np.pi * w[d - 1])) ** 2) 78 | 79 | sum1 = 0 80 | for ii in range(d - 1): 81 | wi = w[ii] 82 | new = (wi - 1) ** 2 * (1 + 10 * (np.sin(np.pi * wi + 1)) ** 2) 83 | sum1 = sum1 + new 84 | 85 | y = term1 + sum1 + term3 86 | return y 87 | 88 | 89 | # 函数测试 90 | for i in range(10): 91 | result = OPSO(20, 30, -10, 10, 1000, Sphere) 92 | print(result) 93 | -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/code/python/PSO_GBEST.py: -------------------------------------------------------------------------------- 1 | # coding:陈小斌 2 | # GitHub:doFighter 3 | import numpy as np 4 | 5 | 6 | def PSO_GBEST(N, dim, x_min, x_max, iterate_max, fitness): 7 | """ 8 | PSO算法最开始的版本(doi:10.1109/icnn.1995.488968) 9 | :param N: 粒子数目 10 | :param dim: 问题维度 11 | :param x_min: 搜索空间下限 12 | :param x_max: 搜索空间上限 13 | :param iterate_max: 最大迭代次数 14 | :param fitness: 评价函数 15 | :return: 返回当前搜索到的最佳适应值 16 | """ 17 | c1 = 2 18 | c2 = 2 19 | v_max = x_max * 0.2 20 | v_min = x_min * 0.2 21 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 22 | v = v_min + (v_max - v_min) * np.random.random([N, dim]) 23 | pBest = x 24 | # 获取初始时全局最优位置 25 | gBest = pBest[0, :] 26 | for i in range(1, N): 27 | if fitness(gBest) > fitness(pBest[i, :]): 28 | gBest = pBest[i, :] 29 | pBest_res = np.ones([N]) 30 | iterate = 0 31 | while iterate < iterate_max: 32 | v = v + c1 * np.random.random([N, dim]) * (pBest - x) + \ 33 | c2 * np.random.random([N, dim]) * (gBest - x) 34 | # 对速度或位置超出规定的做相应的纠正 35 | v[v > v_max] = v_max 36 | v[v < v_min] = v_min 37 | x = x + v 38 | x[x > x_max] = x_max 39 | x[x < x_min] = x_min 40 | # 更新各粒子的历史最优位置 41 | for i in range(N): 42 | if fitness(pBest[i, :]) > fitness(x[i, :]): 43 | pBest[i, :] = x[i, :] 44 | pBest_res[i] = fitness(pBest[i, :]) 45 | # 更新全局最优位置 46 | if pBest_res.min() < fitness(gBest): 47 | index = np.where(pBest_res == pBest_res.min()) 48 | gBest = pBest[index[0][0], :] 49 | 50 | iterate += 1 51 | res = fitness(gBest) 52 | return res 53 | 54 | 55 | def Sphere(xx): 56 | """ 57 | Sphere Function 58 | :param xx: 疑似最优解 59 | :return:适应度值 60 | """ 61 | d = len(xx) 62 | sum = 0 63 | for i in range(d): 64 | sum += xx[i] ** 2 65 | return sum 66 | 67 | 68 | # 函数测试 69 | result = PSO_GBEST(20, 30, -10, 10, 1000, Sphere) 70 | print(result) 71 | -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/code/python/PSO_LBEST_distance.py: -------------------------------------------------------------------------------- 1 | # coding:陈小斌 2 | # GitHub:doFighter 3 | import numpy as np 4 | 5 | 6 | def PSO_LBEST_distance(N, dim, x_min, x_max, iterate_max, fitness): 7 | """ 8 | 二邻域结构:在本代码中,该邻域结构是距离相邻,即真正意义上的空间结构相邻(doi:10.1109/MHS.1995.494215) 9 | :param N: 粒子种群大小 10 | :param dim: 问题解的维度 11 | :param x_min: 解空间的下限 12 | :param x_max: 解空间的上限 13 | :param iterate_max: 迭代上限 14 | :param fitness: 评价函数 15 | :return: 迭代中适应度最优的值 16 | """ 17 | c = 2 * np.ones([3, 1]) 18 | v_max = 0.2 * x_max 19 | v_min = 0.2 * x_min 20 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 21 | v = v_min + (v_max - v_min) * np.random.random([N, dim]) 22 | pBest = x 23 | results = np.inf * np.ones([iterate_max, 1]) 24 | res = np.inf * np.ones([N, 1]) 25 | iterate = 0 26 | while iterate < iterate_max: 27 | for i in range(N): 28 | # 获取粒子群结构中空间相邻的二领域结构 29 | temp = np.delete(pBest, i, axis=0) 30 | distance = np.sum((pBest[i, :] - temp) ** 2, 1) 31 | sort_distance = np.sort(distance) 32 | position = np.where(distance <= sort_distance[1]) 33 | position = position[0] 34 | pre = position[0] 35 | nex = position[1] 36 | 37 | v[i, :] = v[i, :] + c[0] * np.random.random([1, dim]) * (pBest[i, :] - x[i, :]) + c[1] * np.random.random( 38 | [1, dim]) * (pBest[pre, :] - x[i, :]) + c[2] * np.random.random([1, dim]) * (pBest[nex, :] - x[i, :]) 39 | v[v > v_max] = v_max 40 | v[v < v_min] = v_min 41 | x += v 42 | x[x > x_max] = x_max 43 | x[x < x_min] = x_min 44 | for i in range(N): 45 | if fitness(x[i, :]) < fitness(pBest[i, :]): 46 | pBest[i, :] = x[i, :] 47 | res[i] = fitness(pBest[i, :]) 48 | results[iterate] = min(res) 49 | iterate += 1 50 | return min(results) 51 | 52 | 53 | def Sphere(xx): 54 | """ 55 | Sphere Function 56 | :param xx: 疑似最优解 57 | :return:适应度值 58 | """ 59 | d = len(xx) 60 | sum = 0 61 | for i in range(d): 62 | sum += xx[i] ** 2 63 | return sum 64 | 65 | 66 | # 函数测试 67 | result = PSO_LBEST_distance(20, 30, -10, 10, 10000, Sphere) 68 | print(result) 69 | -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/code/python/PSO_LBEST_logic.py: -------------------------------------------------------------------------------- 1 | # coding:陈小斌 2 | # GitHub:doFighter 3 | import numpy as np 4 | 5 | 6 | def PSO_LBEST_logic(N, dim, x_min, x_max, iterate_max, fitness): 7 | """ 8 | 二邻域结构:在本代码中,该邻域结构是逻辑相邻,即存储的地址下标相邻(doi:10.1109/MHS.1995.494215) 9 | :param N: 粒子种群大小 10 | :param dim: 问题解的维度 11 | :param x_min: 解空间的下限 12 | :param x_max: 解空间的上限 13 | :param iterate_max: 迭代上限 14 | :param fitness: 评价函数 15 | :return: 迭代中适应度最优的值 16 | """ 17 | c = 2 * np.ones([3, 1]) 18 | v_max = 0.2 * x_max 19 | v_min = 0.2 * x_min 20 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 21 | v = v_min + (v_max - v_min) * np.random.random([N, dim]) 22 | pBest = x 23 | results = np.inf * np.ones([iterate_max, 1]) 24 | res = np.inf * np.ones([N, 1]) 25 | iterate = 0 26 | while iterate < iterate_max: 27 | for i in range(N): 28 | pre = i - 1 29 | nex = i + 1 30 | if pre < 0: 31 | pre = N - 1 32 | if nex > (N - 1): 33 | nex = 1 34 | v[i, :] = v[i, :] + c[0] * np.random.random([1, dim]) * (pBest[i, :] - x[i, :]) + c[1] * np.random.random( 35 | [1, dim]) * (pBest[pre, :] - x[i, :]) + c[2] * np.random.random([1, dim]) * (pBest[nex, :] - x[i, :]) 36 | v[v > v_max] = v_max 37 | v[v < v_min] = v_min 38 | x += v 39 | x[x > x_max] = x_max 40 | x[x < x_min] = x_min 41 | for i in range(N): 42 | if fitness(x[i, :]) < fitness(pBest[i, :]): 43 | pBest[i, :] = x[i, :] 44 | res[i] = fitness(pBest[i, :]) 45 | results[iterate] = min(res) 46 | iterate += 1 47 | return min(results) 48 | 49 | 50 | def Sphere(xx): 51 | """ 52 | Sphere Function 53 | :param xx: 疑似最优解 54 | :return:适应度值 55 | """ 56 | d = len(xx) 57 | sum = 0 58 | for i in range(d): 59 | sum += xx[i] ** 2 60 | return sum 61 | 62 | 63 | # 函数测试 64 | result = PSO_LBEST_logic(20, 30, -10, 10, 1000, Sphere) 65 | print(result) 66 | -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/images/PSO流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/经典粒子群优化/images/PSO流程图.png -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/images/粒子速度与位置在二维空间更新.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/经典粒子群优化/images/粒子速度与位置在二维空间更新.png -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/粒子群优化一.md: -------------------------------------------------------------------------------- 1 | # 粒子群优化 一 2 | 3 | ## 1 思想来源 4 | 5 | **粒子群优化(Particle Swarm Optimization,PSO)** 作为进化计算的一个分支,是由 Eberhart 和 Kennedy 于 1995 提出的一种搜索算法。该算法在提出时是为了优化非线性函数,亦即求解非线性函数在某个求解范围内的最优解。 6 | 7 | 粒子群优化是一种模拟自然界生物的活动以及群体智能的随机搜索算法,该算法吸取了**人工生命(Artificial Life)**、**鸟群觅食(Birds Flocking)**、**鱼群学习(Fish Schooling)** 和 **群理论(Swarm Theory)** 的思想,通过对以上群体智能行为的抽象模仿,从而缔造出**粒子群优化** 。从这我们也可以看出,粒子群优化,其本质就是一种 **群体智能优化** ,该优化算法就是通过模拟生物群体在觅食或者躲避天敌时展现的群体智能行为而产生的。 8 | 9 | ## 2 基本原理 10 | 11 | ### 2.1 群体智能(Swarm Intelligence) 12 | 13 | 在自然界中,鸟类是通过什么养的机制发现猎物的呢?或许,我们很少见到鸟群协同寻找食物,但是在动物世界中,我们经常可以看到庞大的鱼群聚集在一起躲避被猎杀。以及狼群和猎狗等等,它们是如何发现猎物的呢? 14 | 15 | 当我们不断剖析其中原因,会发现,狼群以及猎狗在发现猎物之后会通过声音向同伴传递信息,使得同伴不断向猎物所在地不断聚集。而对于其他的亦是如此,虽然我们无法理解鸟群以及鱼群是如何进行协同配合来躲避天敌或是寻找食物,但是在它们之间一定是存在某种可供交流的机制,使得各个个体之间的信息、经验能够互享,随着群体中经验的累加,就会展现出一种超越个体的 **群体智能** ,这也是我们为什么说人多力量大,其实人类也是具有群体智能的,并且我们老祖宗很早之前就已经得出这个结论。 16 | 17 | ### 2.2 算法原理 18 | 19 | 在上文我们已经分析了群体智能的基本原理,现在最关键的,便是如何将其要素进行抽象,最后变成能够进行编程的规则要求。 20 | 21 | 在之前的场景中已经提出,一群分散寻找食物的狼或者猎狗,我们以狼群为例,一开始并不知道猎物的所在,但是会有一个间接的机制会让狼群知道猎物的所在,比如猎物留下的足迹以及气味等。于是狼就会随着这些痕迹不断分散搜索,寻找气味最浓的位置方向,并通过声音或其他信息交流的方式通知其他狼,以此不断调整整个群体的位置,保证不断向猎物逼近,以至于最后发现猎物并捕食。这样,狼群中的每个个体都有了一个指导方向,总体的方向是猎物的方向,在这个过程中,所有个体不断地配合,根据自身的经验以及整个群体的经验调整自己的速度以及跟踪方向。 22 | 23 | >在很多的文献当中,更多的是以鸟群为例,但是在我个人理解看来,对于鸟群觅食,我们见的少之又少,对于理解这些概念或许有些不太适合。而对于狼群或者猎狗,却是再合适不过。此外,在上面的小标题中,我写的是 **群体智能** ,而不是粒子群智能,这也是我对于该算法的考虑。在我看来,它的重心,亦即算法核心在于群体协同所产生超乎个体的智能,所以我更愿意将它称之为 **群体智能** ,至于该优化算法的名字中的 **粒子** 一词,其实是将群体中的个体抽象为一个点,一个带有位置速度等性质的点,我们称之为 **粒子**。 24 | 25 | - 下面通过一个表格以狼群捕食和粒子群优化算法的基本定义进行对照 26 | 27 | | 狼群捕食 | 粒子群优化算法 | 28 | | -------- | ----------------------------------------------- | 29 | | 狼群 | 在搜索空间进行搜索的所有有效解(也就是种群规模N) | 30 | | 捕食空间 | 问题搜索空间(即解的维数,也就是未知数个数) | 31 | | 捕食范围 | 求解问题的范围(即解的取值范围) | 32 | | 追赶速度 | 解的速度向量$v_i=[v_i^1,v_i^2,\dotsb,v_i^D]$ | 33 | | 自身位置 | 有效解的位置$x_i=[x_i^1,x_i^2,\dotsb,x_i^D]$ | 34 | | 个体认知 | 粒子根据自身历史最优位置更新自身速度和位置 | 35 | | 群体认知 | 粒子根据全局最优位置更新自身速度和位置 | 36 | | 捕获猎物 | 算法结束,输出当前全局最优解 | 37 | 38 | >在智能算法领域,却有人提出了狼群算法,所以有必要进行解释,在该文只是以狼群的行为帮助大家更好的理解粒子群优化算法,所以在这里进行注明。 39 | 40 | ## 3 粒子群优化算法基本流程 41 | 42 | ### 3.1 基本流程 43 | 44 | 粒子群优化(PSO)要求每个个体(粒子)在进化的过程中维护两个向量,分别是速度向量$v_i=[v_i^1,v_i^2,\dotsb,v_i^D]$和位置向量$x_i=[x_i^1,x_i^2,\dotsb,x_i^D]$,其中$i$是指粒子的编号,$D$是求解问题空间的维数(通俗一点就是未知数的个数)。粒子的速度决定了自身运动的方向和速率,而其所处的位置则是解空间中的一个可行解,然后通过特定的评价方式以及评价函数评价该解的优劣。 45 | 46 | #### 3.1.1 两个主要变量 47 | 48 | - 自身历史最优($pBest$) 49 | 在该算法中,每个粒子还需要维护自身的历史最优位置 $pBest$。也就是每次粒子到达一个位置,都会通过指定的评价函数以及评价方式对该位置的解进行评价,如若此时得到的解的质量要优于之前的历史最优解,则更新该粒子的历史最优位置。所以在该算法不断优化的过程中,该粒子的最优位置也就在不断地改变,$pBest$ 向量也就在不断地更新 50 | 51 | - 全局最优($gBest$) 52 | 除了需要进行局部最优的维护,另一个就是全局最优位置的维护,使用$gBest$来表示。有了局部最优就相当于狼群中的每只狼都有自己搜索得到最好的结果,然后传递给同伴,也就是整个狼群。狼群通过分析所有的局部最优结果,得到一个全局的最优结果。所以全局最优就是在局部最优内再挑选出其内最优的结果。这个全局最优将会对所有粒子都会有引导作用,使得整个种群往全局最优位置收敛。 53 | 54 | - PSO 的算法步骤如下: 55 | 1. 种群初始化:初始化种群中各粒子的速度和位置,分别按照公式(1)和公式(2)。并将个体历史最优$pBest$设为当前值,将种群最优的个体作为当前$gBest$值。 56 | 2. 迭代搜索,计算每次迭代后的粒子位置的适应度函数值(也就是评判粒子的质量)。 57 | 3. 判断当前粒子的质量是否优于历史最优,如是,则将历史最优值设置为当前值;如不是,则不进行操作。 58 | 4. 判断当前全局最优值是否优于历史的全局最优值,如是,则更新全局最优值;否则,不进行操作。 59 | 5. 对粒子进行速度和位置的更新,更新方式如公式$(3)$,公式$(4)$。 60 | 6. 如果没有达到结束条件,转到步骤(2),否则输出 $gBest$并结束。 61 | 62 | $$ 63 | x_i^d = x_{min} + (x_{max}-x_{min})\times rand_i^d\tag{1} 64 | $$ 65 | $$ 66 | v_i^d = v_{min} + (v_{max}-v_{min})\times rand_i^d\tag{2} 67 | $$ 68 | >一般在开始时,就会需要确定求解函数解的范围,所以$x_{min}以及x_{max}$就能在此时进行确定。而$v_{min}以及v_{max}$则一般取解的范围的10%~20%。 69 | 70 | $$ 71 | v_i^d=v_i^d+c_1\times rand_i^d\times (pBest_i^d-x_i^d)+c_2\times rand_i^d\times(gBest^d-x_i^d) \tag{3} 72 | $$ 73 | $$ 74 | x_i^d=x_i^d+v_i^d \tag{4} 75 | $$ 76 | 77 | PSO 粒子依靠速度和位置在二维空间中更新示意图如下所示: 78 | 79 | ![ref](./images/粒子速度与位置在二维空间更新.png) 80 | 81 | 在公式(3)中,$c_1,c_2$是加速系数(Acceleration Coefficients,也称 **学习因子**),在原论文中建议取固定值2.0。$rand_1^d和rand_2^d$是两个在区间[0,1]上的随机数。在更新过程中,需要对速度进行限制,速度一般限制在解的取值范围的10%~20%内。对于公式(4),位置更新必须是合法的,所以在每次进行更新之后都要检查更新后的位置是否在问题空间中,如不在,则需要进行必要的修正,修正的方法可以是重新随机设定或者限定在边界。 82 | 83 | - PSO流程图如下: 84 | ![ref](./images/PSO流程图.png) 85 | 86 | ## 参考文献 87 | 88 | [1]Kennedy, J. and R. Eberhart (1995). Particle Swarm Optimization. Icnn95-international Conference on Neural Networks. IEEE, 1995, 4: 1942-1948. 89 | [2]张军,詹志辉等.计算智能[M].北京:清华大学出版社,2009. 90 | -------------------------------------------------------------------------------- /粒子群优化算法/经典粒子群优化/粒子群优化二.md: -------------------------------------------------------------------------------- 1 | # 粒子群优化 二 2 | 3 | >在第一部分讲述了关于粒子群优化的原理,以及算法的整体流程结构,在这一部分,我们将会介绍在早期经典的PSO算法,并使用 MATLAB 以及 python 编写代码。相关代码请见 code 文件夹。 4 | 5 | ## 1 再论粒子群优化 6 | 7 | 粒子群优化中,越过最优的个体会被拉回去,所有粒子都保留了良好解决方案的知识。此外粒子群优化是有记忆的,在运行过程中会把历史最优粒子的位置进行记录,并且在后面的运行过程中不断对后面的粒子进行引导。 8 | 在《**A New Optimizer Using Particle Swarm Theory**》 一文中,作者 Russell Eberhart 和 James Kennedy 进一步论述了粒子群优化算法,在该文中描述了使用粒子群方法对非线性函数的优化。 讨论并比较了两种范式的实现,包括最近开发的面向本地的范式,描述了这两种范例的基准测试。在这其中提出的两种范式便是粒子群优化算法(Particle Swarm Optimization,PSO)的两种形式,但是一般我们更容易见到其中一种,也就是**GBEST** 模型,在第一次描述PSO算法中,就是以GBEST为例进行举例。除却 GBEST模型,在该文中还提出另外一种模型,那就是**LBEST** 模型。下面,我们将细致地介绍这两种模型。 9 | 10 | ## 2 GBEST模型 11 | 12 | 在之前已经介绍了粒子群优化算法的思想来源以及定义的对照表,所以想必大家对**gbest** 是有印象的。在第一篇文章中,我们将其称之为全局最优解。标准的“ GBEST”粒子群算法非常简单,它是开发的粒子群优化的原始形式。 13 | 14 | ### 2.1 算法执行流程 15 | 16 | > - Step1:初始化种群,也即粒子数N,同时初始化每个粒子的速度和初始位置,维度为解的维度。 17 | > - Step2:初始化pbest以及gbest,并给其赋初始值,可选择取值边界。定义最大迭代次数以及起始迭代值。这个设置就需要根据语言而定,比如MATLAB,其下标是从1开始,所以一般起始迭代我们设置为1. 18 | > - Step3:对每一个粒子位置进行适应性评估,倘若当前位置优于历史最优位置,则更新该粒子的历史最优解。 19 | > - Step4:从所有粒子的历史最优解获取适应性最优的那个位置,并与当前全局最优位置gbest适应性进行比较,如果适应性大于当前位置,则更新全局最优位置。 20 | > - Step5:按照公式更新粒子速度,更新速度公式为:$v_i^d=v_i^d+c1\times rand_i^d\times (pBest_i^d-x_i^d)+c2\times rand_i^d\times (gBest^d-x_i^d)$ 21 | > - Step6:判断粒子速度是否超过取值范围,将超过取值范围的重新赋值(可以赋值为边界值,或者重新随机生成)。 22 | > - Step7:按照公式更新粒子位置,更新粒子位置公式为:$x_i^d=x_i^d+v_i^d$ 23 | > - Step8:判断粒子位置是否超过取值范围,将超过取值范围的重新赋值(可以赋值为边界值,或者重新随机生成)。 24 | > - Step9:判断迭代次数是否大于最大迭代次数,如不大于,则跳至Step3。否则输出最优解 25 | 26 | ## 3 LBEST 模型 27 | 28 | 除了GBEST模型之外,在这之后还提出了LBEST模型。在这种模型中,粒子仅具有自己的信息以及邻居的信息,而不是整个团队的全局最优信息。也就是说粒子没有了全局最优导向粒子,在这个过程中只会接收按照排序位置相邻的粒子的信息。粒子朝着由“pbest”和“ lbest”定义的点移动,而不是朝着“pbest”和“gbest”位置进行移动。这样的模型,粒子的多样性得到了很大程度上的维护,但是当粒子的相邻位置适应度较差时,粒子的适应值也会变差,同时,优于粒子的分布过于分散,导致粒子即使发现较好位置,也没有足够的粒子进行开发。可能会使其整体解的质量下降。 29 | 那么LBEST模型是如何进行更新的呢?在邻域= 2模型中,粒子(i)将其误差值与粒子(i-1)和粒子(i + 1)进行比较。 30 | 在这里,我们使用领域=2的模型进行描述。它的基本步骤和GBEST类似,只不过在更新的时候略有变化,同时也不再需要gbest变量来存储全局最优。 31 | 32 | ### 3.1 算法执行流程 33 | 34 | > - Step1:初始化种群,也即粒子数N,同时初始化每个粒子的速度和初始位置,维度为解的维度。 35 | > - Step2:初始化pbest,并给其赋初始值,可选择取值边界。定义最大迭代次数以及起始迭代值。这个设置就需要根据语言而定,比如MATLAB,其下标是从1开始,所以一般起始迭代我们设置为1. 36 | > - Step3:对每一个粒子位置进行适应性评估,倘若当前位置优于历史最优位置,则更新该粒子的历史最优解。 37 | > - Step4:按照公式更新粒子速度,更新速度公式为:$v_i^d=v_i^d+c1\times rand_i^d\times (pBest_i^d-x_i^d)+c2\times rand_{i-1}^d\times (x_{i-1}^d-x_i^d)+c3\times rand_{i+1}^d\times (x_{i+1}^d-x_i^d)$;在这里需要注意,我们采取首尾相连的措施,也就是第一个粒子的前一个粒子是最后一个粒子,同理,最后一个粒子的后一个粒子就是第一个粒子。 38 | > - Step5:判断粒子速度是否超过取值范围,将超过取值范围的重新赋值(可以赋值为边界值,或者重新随机生成)。 39 | > - Step6:按照公式更新粒子位置,更新粒子位置公式为:$x_i^d=x_i^d+v_i^d$ 40 | > - Step7:判断粒子位置是否超过取值范围,将超过取值范围的重新赋值(可以赋值为边界值,或者重新随机生成)。 41 | > - Step8:判断迭代次数是否大于最大迭代次数,如不大于,则跳至Step3。否则输出最优解 42 | 43 | ### 3.2 非常重要 44 | 45 | 在邻域模型中,存在着很多邻域结构:例如二邻域、三邻域等多邻域结构,但是这些类似结构的编程方法都类似,无需多言。 46 | 47 | 但是在邻域模型中有一个非常重要的点,那就是对邻域的理解,或者说定义。一般说来可以分为两种: 48 | 49 | - 第一种:逻辑上的邻域。在粒子群进行搜索的时候,每个粒子都会有一个位置下标,就如同我们给每个粒子进行编号一样,并且该编号不会随着后续程序的运行而发生改变。在该基础上实现多邻域粒子群优化代码会更加简单。但是会存在问题,那就是所谓的邻域粒子除了逻辑上相邻之外,在物理上并不相邻,因此在物理上或许并不能称为邻域。 50 | - 第二种:物理上的邻域。从上面就可以很快明白,物理上的邻域就是在搜索过程中在粒子 $i$ 身边的粒子,因此在这种邻域结构中,就需要额外计算个粒子的相邻粒子,再根据计算的结果进行邻域更新。因此第二种邻域结构更符合正常的思维,但是要付出更大的空间以及时间。 51 | 52 | ## 4 $\omega$模型 53 | 54 | Yuhui Shi 和 Russell Eberhart在1998年发表的一篇名叫《 **A Modified Particle Swarm Optimizer**》中对之前提出的GBEST模型进行进一步的分析,再该论文中,他们指出:该模型中的公式(1)是由三部分组成:第一部分是粒子的先前速度;第二和第三部分是有助于粒子速度变化的部分。通过公式(1)我们可以看到,如果没有$c1\times rand_i^d\times (pBest_i^d-x_i^d)$和$c2\times rand_i^d\times (gBest^d-x_i^d)$这两部分,那么粒子就会在速度所指向的方向直线来回运动,无法去探索更广泛的区域。除非解就在它们运行的直线上,还必须是在粒子所能到达的点的位置,否则无法寻找到最优解。 55 | 56 | $$ 57 | v_i^d=v_i^d+c1\times rand_i^d\times (pBest_i^d-x_i^d)+c2\times rand_i^d\times (gBest^d-x_i^d) \tag{1} 58 | $$ 59 | 60 | 但是当没有第一部分时,粒子的飞行速度将只会受到局部最优位置以及全局最优位置的影响。当该是全局最优的时候,那么该粒子就会停在原地,直到其他粒子找到一个更优的解。 61 | 62 | 所以从上面的描述我们可以看出,**当粒子速度更新公式中缺少第一部分的时候,那么该粒子群展示的是局部搜索能力:“因为此时所有粒子都会围绕在全局最优处”。而当保留第一部分的时候,它其实是扩大了粒子群搜索空间,使得他们更有能力搜索到新的区域。** 63 | 64 | **因此,通过添加第一部分,更有可能具有全局搜索能力。局部搜索和全局搜索都有助于解决某些类型的问题。 全局搜索和局部搜索之间存在权衡对于不同的问题,局部搜索能力和全局搜索能力之间应该有不同的平衡。** 考虑到这一点,将惯性权重w引入等式(1)中,如等式(2)所示。 这个 w 起到平衡全局搜索和局部搜索的作用,它可以是正常数,甚至是时间的正线性或非线性函数。 65 | 66 | $$ 67 | v_i^d=\omega v_i^d+c1\times rand_i^d\times (pBest_i^d-x_i^d)+c2\times rand_i^d\times (gBest^d-x_i^d) \tag{2} 68 | $$ 69 | 同时,作者在论文也做了相关测试,从测试的数据可以发现:“范围[0.9,1.21] 是使用$\omega$得到效果最好的区域。 $\omega$ 在这个范围内的 PSO 将有更大的概率在合理的迭代次数找到全局最优值。 在该文的测试中,发现当 $\omega$=1.05时,PSO在迭代运行30次时都找到了全局最优值。 当 $\omega$ 在[0.9,1.2] 的范围内取值时,发现当$\omega$ = 0.9时,PSO 找到全局最优值的所需的平均迭代次数是最少的。” 70 | 71 | >原文中也指出最优的方式 $\omega$ 一般是在[0.9,0.5]范围内线性递减 72 | 73 | ### 4.1 算法执行流程 74 | 75 | 该算法和 **GBSET** 模型的流程是一模一样的,唯一改变,就是速度更新公式由公式(1)改为公式(2).所以这里不再赘述该模型的算法流程。 76 | 77 | ## 源代码 78 | 79 | > - **相应的代码在对应文件夹的code下,请需要者自行获取** 80 | 81 | ## 参考文献 82 | 83 | [1]Eberhart, R. and J. Kennedy (1995). A new optimizer using particle swarm theory. Mhs95 Sixth International Symposium on Micro Machine & Human Science. 84 | [2]Shi, Y. (1998). A Modified Particle Swarm Optimizer. Proc of IEEE Icec Conference. 85 | -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/code/matlab/FunCLPSO_Version1.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 广泛学习粒子群优化:版本一——按照流程图的方式书写代码 3 | % coding:陈小斌 4 | % Github:doFighter 5 | % N: 种群大小 6 | % dim:求解问题的维度 7 | % x_max:解空间上限 8 | % x_min:解空间下限 9 | % iterate_max:最大迭代次数 10 | % fitness:评价函数 11 | %% --------------------------------------------------------------------%% 12 | function [result] = FunCLPSO_Version1(N,dim, x_max,x_min,iterate_max,fitness) 13 | c = 2*ones(1,2); % 定义加速系数 c1,c2;这里直接放入一个矩阵中,这是经典PSO需要 14 | c1 = 1.49445; % CLPSO 速度更新时用到的系数 15 | %获取各粒子广泛学习概率Pc 16 | Pc = zeros(N,1); 17 | for i=1:N 18 | Pc(i) = 0.05 + 0.45*(exp((10*(i-1)/(N-1))-1)/(exp(10)-1)); 19 | end 20 | flag = zeros(N,1); %用于记录粒子有多少次未曾进行速度迭代 21 | m = 7; %刷新间隔 22 | %由于在文中未能看到上面的 rand 是随机生成亦或是初始化生成,这里使用随机生成 23 | v_min = x_min*0.2; 24 | v_max = x_max*0.2; 25 | x = x_min + (x_max-x_min)*rand(N,dim); % 初始化种群位置;三行两列的矩阵,元素处于-10~10之间。三行寓意为种群,两列为维度. 26 | v = v_min + (v_max-v_min)*rand(N,dim); % 初始化种群速度;速度一般在位置的取值范围的10%~20%,这里取10% 27 | pBest = x; % 存储粒子的局部最优值,初始为 初始值 28 | gBest = x(1,:); % 存储粒子的全局最优值 29 | for i = 2:N 30 | if fitness(gBest) > fitness(pBest(i,:)) 31 | gBest = pBest(i,:); 32 | end 33 | end 34 | 35 | iterate = 1; 36 | while iterate < iterate_max+1 37 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 -10~10 时,将其也置为边界数 38 | omega = 0.9 - 0.5*((iterate-1)/iterate_max); 39 | for i=1:N 40 | if flag(i)>=m 41 | v(i,:) = omega*v(i,:) + c(1)*rand(1,dim).*(pBest(i,:)-x(i,:)) + c(2)*rand(1,dim).*(gBest-x(i,:)); 42 | flag(i) = 0; 43 | end 44 | pBest_fi = pBest(i,:); 45 | rd = rand(1,dim); 46 | position = find(rdv_max) = v_max; 64 | vi(vix_max|xi fitness(pBest(i,:)) 31 | gBest = pBest(i,:); 32 | end 33 | end 34 | 35 | iterate = 1; 36 | while iterate < iterate_max+2 37 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 -10~10 时,将其也置为边界数 38 | omega = 0.9 - 0.5*((iterate-1)/iterate_max); 39 | for i=1:N 40 | if flag(i)>=m 41 | v(i,:) = omega*v(i,:) + c(1)*rand(1,dim).*(pBest(i,:)-x(i,:)) + c(2)*rand(1,dim).*(gBest-x(i,:)); 42 | flag(i) = 0; 43 | end 44 | rd = rand(1,dim); 45 | pBest_fi = pBest(i,:); 46 | if isempty(rdv_max) = v_max; 68 | vi(vix_max|xi fitness(x(i,:)) 33 | gBest = x(i,:); 34 | end 35 | end 36 | 37 | iterate = 1; 38 | while iterate < iterate_max+1 39 | % 下面进行速度与位置的更新,当速度超出 -2~2 时,将其置为边界数,同理,当位置超出 -10~10 时,将其也置为边界数 40 | omega = 0.9 - 0.5*((iterate-1)/iterate_max); 41 | for i=1:N 42 | if flag(i)>=m 43 | v(i,:) = omega*v(i,:) + c(1)*rand(1,dim).*(pBest(i,:)-x(i,:)) + c(2)*rand(1,dim).*(gBest-x(i,:)); 44 | flag(i) = 0; 45 | end 46 | pBest_fi = pBest(i,:); 47 | rd = rand(1,dim); 48 | P_index = (1:N); 49 | P_index(i) = []; 50 | position = find(rdv_max) = v_max; 69 | vi(vix_max|xi fitness(x[i, :]): 33 | gBest = x[i, :].copy() 34 | iterate = 0 35 | while iterate < iterate_max: 36 | omega = 0.9 - 0.5 * (iterate / iterate_max) 37 | for i in range(N): 38 | if flag[i] >= m: 39 | v[i, :] = omega * v[i, :] + c[0] * np.random.random([1, dim]) * ( 40 | pBest[i, :] - x[i, :]) + c[1] * np.random.random([1, dim]) * (gBest - x[i, :]) 41 | flag[1] = 0 42 | pBest_fi = pBest[i, :] 43 | rd = np.random.random(dim) 44 | position = np.where(rd < Pc[i]) 45 | position = position[0] 46 | for j in position: 47 | pBest_f1 = pBest[i, :].copy() 48 | pBest_f2 = pBest[i, :].copy() 49 | f1 = int(np.ceil(np.random.random() * (N - 1))) 50 | f2 = int(np.ceil(np.random.random() * (N - 1))) 51 | pBest_f1[j] = pBest[f1, j] 52 | pBest_f2[j] = pBest[f2, j] 53 | if fitness(pBest_f1) < fitness(pBest_f2): 54 | pBest_fi[j] = pBest_f1[j] 55 | else: 56 | pBest_fi[j] = pBest_f2[j] 57 | v[i, :] = omega * v[i, :] + c1 * \ 58 | np.random.random([1, dim]) * (pBest_fi - x[i, :]) 59 | vi = v[i, :] 60 | vi[vi > v_max] = v_max 61 | vi[vi < v_min] = v_min 62 | x[i, :] = x[i, :] + vi 63 | xi = x[i, :] 64 | if len(xi[(xi > x_max) | (xi < x_min)]) == 0: 65 | if fitness(xi) < fitness(pBest[i, :]): 66 | pBest[i, :] = xi.copy() 67 | flag[i] = 0 68 | if fitness(xi) < fitness(gBest): 69 | gBest = xi.copy() 70 | else: 71 | flag[i] += 1 72 | iterate += 1 73 | result = fitness(gBest) 74 | return result 75 | 76 | 77 | def Sphere(xx): 78 | """ 79 | Sphere Function 80 | :param xx: 疑似最优解 81 | :return:适应度值 82 | """ 83 | d = len(xx) 84 | sum = 0 85 | for i in range(d): 86 | sum += xx[i] ** 2 87 | return sum 88 | 89 | 90 | # 函数测试 91 | for i in range(10): 92 | result = CLPSO_Version1(20, 30, -10, 10, 1000, Sphere) 93 | print(result) 94 | -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/code/python/CLPSO_Version2.py: -------------------------------------------------------------------------------- 1 | # coding:陈小斌 2 | # GitHub:doFighter 3 | import numpy as np 4 | 5 | 6 | def CLPSO_Version2(N, dim, x_min, x_max, iterate_max, fitness): 7 | """ 8 | CLPSO版本二:广泛学习粒子群优化,较版本一增加了当某个粒子所有维度都不进行学习时,就任意选择一个维度进行学习 9 | :param N: 粒子种群大小 10 | :param dim: 问题解的维度 11 | :param x_min: 求解问题的解空间下限 12 | :param x_max: 求解问题的解空间上限 13 | :param iterate_max: 最大迭代次数 14 | :param fitness: 评价函数,即求解函数 15 | :return: result,最优解 16 | """ 17 | c = 2 * np.ones([2, 1]) 18 | c1 = 1.49445 19 | Pc = np.zeros([N, 1]) 20 | for i in range(N): 21 | Pc[i] = 0.05 + 0.45 * \ 22 | (np.exp((10 * (i - 1) / (N - 1) - 1) / np.exp(10) - 1)) 23 | flag = np.zeros([N, 1]) 24 | m = 7 25 | v_max = 0.2 * x_max 26 | v_min = 0.2 * x_min 27 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 28 | v = v_min + (v_max - v_min) * np.random.random([N, dim]) 29 | pBest = x 30 | gBest = x[0, :].copy() 31 | for i in range(1, N): 32 | if fitness(gBest) > fitness(x[i, :]): 33 | gBest = x[i, :].copy() 34 | iterate = 0 35 | while iterate < iterate_max: 36 | omega = 0.9 - 0.5 * (iterate / iterate_max) 37 | for i in range(N): 38 | if flag[i] >= m: 39 | v[i, :] = omega * v[i, :] + c[0] * np.random.random([1, dim]) * (pBest[i, :] - x[i, :]) + c[ 40 | 1] * np.random.random([1, dim]) * (gBest - x[i, :]) 41 | flag[1] = 0 42 | pBest_fi = pBest[i, :] 43 | rd = np.random.random(dim) 44 | position = np.where(rd < Pc[i]) 45 | position = position[0] 46 | if len(position) == 0: 47 | pBest_fi[int(np.ceil(np.random.rand() * (dim - 1)))] = pBest[int(np.ceil( 48 | np.random.rand() * (N - 1))), int(np.ceil(np.random.rand() * (dim - 1)))] 49 | else: 50 | for j in position: 51 | pBest_f1 = pBest[i, :].copy() 52 | pBest_f2 = pBest[i, :].copy() 53 | f1 = int(np.ceil(np.random.random() * (N - 1))) 54 | f2 = int(np.ceil(np.random.random() * (N - 1))) 55 | pBest_f1[j] = pBest[f1, j] 56 | pBest_f2[j] = pBest[f2, j] 57 | if fitness(pBest_f1) < fitness(pBest_f2): 58 | pBest_fi[j] = pBest_f1[j] 59 | else: 60 | pBest_fi[j] = pBest_f2[j] 61 | v[i, :] = omega * v[i, :] + c1 * \ 62 | np.random.random([1, dim]) * (pBest_fi - x[i, :]) 63 | vi = v[i, :] 64 | vi[vi > v_max] = v_max 65 | vi[vi < v_min] = v_min 66 | x[i, :] = x[i, :] + vi 67 | xi = x[i, :] 68 | if len(xi[(xi > x_max) | (xi < x_min)]) == 0: 69 | if fitness(xi) < fitness(pBest[i, :]): 70 | pBest[i, :] = xi.copy() 71 | flag[i] = 0 72 | if fitness(xi) < fitness(gBest): 73 | gBest = xi.copy() 74 | else: 75 | flag[i] += 1 76 | iterate += 1 77 | result = fitness(gBest) 78 | return result 79 | 80 | 81 | def Sphere(xx): 82 | """ 83 | Sphere Function 84 | :param xx: 疑似最优解 85 | :return:适应度值 86 | """ 87 | d = len(xx) 88 | sum = 0 89 | for i in range(d): 90 | sum += xx[i] ** 2 91 | return sum 92 | 93 | 94 | # 函数测试 95 | result = CLPSO_Version2(20, 30, -10, 10, 1000, Sphere) 96 | print(result) 97 | -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/images/CLPSO-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/综合学习粒子群优化/images/CLPSO-1.jpg -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/images/CLPSO-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/综合学习粒子群优化/images/CLPSO-2.jpg -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/images/CLPSO-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/综合学习粒子群优化/images/CLPSO-3.jpg -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/images/CLPSO-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/综合学习粒子群优化/images/CLPSO-4.jpg -------------------------------------------------------------------------------- /粒子群优化算法/综合学习粒子群优化/综合学习粒子群优化算法.md: -------------------------------------------------------------------------------- 1 | # 综合学习粒子群优化算法 2 | 3 | 本文介绍了一种综合学习的粒子群优化算法,该算法的提出是为了使得粒子群优化在处理多模态问题(即多峰问题)上能够避免算法落入局部最优的风险。文章参考自JJ Liang,AK Qin,PN Suganthan,S Baskar所写的《**Comprehensive learning particle swarm optimizer for global optimization of multimodal functions**》 4 | 5 | ## 1 摘要 6 | 7 | 本文介绍的综合学习粒子群优化算法 (**CLPSO**)是粒子群优化算法 (**PSO**) 的一种变体,它使用一种新颖的学习策略,即使用所有其他粒子的历史最佳信息来更新粒子的速度。 这种策略可以保持群的多样性,以防止过早收敛。 对多模态测试函数(多峰函数)及组合函数进行了相关的测试。 结果表明,与 $PSO$ 的其他最新变体算法相比,$CLPSO$ 在解决多模态问题方面具有良好的性能。 8 | 9 | ## 2 算法介绍 10 | 11 | 在经典的 $PSO$ 算法中,每个粒子的更新都是同时受到 $pbest$ 及 $gbest$ 的影响。同时由于整个种群粒子速度的更新都会受到 $gbest$ 的影响,因此会使得在经典 $PSO$ 算法中算法收敛速度较快。 12 | 13 | 但是这就像是一把双刃剑,收敛过快在经典的 $PSO$ 算法中会产生一个问题,即求解多模态(多峰问题)问题时当一个全局历史最优粒子陷入局部最优,$gbest$ 将会吸引其他粒子陷入该区域,并无法自拔。这将会导致算法无法寻找到全局最优解。 14 | 15 | 然而在经典的 $PSO$ 中一个粒子的适应度的值是通过粒子的所有维度决定的,然而一个粒子在某些维度上发现了与全局最优对应的区域,可能会因为其他维度的解决方案不佳而具有较低的适应度值。为了解决该问题,文献[2]提出使用所有粒子的 $pbest$ 用于更新任何一个粒子的速度,这种新颖的策略确保了群体的多样性,以防止过早收敛。之后在文献[1],即本文主要参考文献,讨论并展示了使用综合学习策略的三个版本的 $PSO$,与 $PSO$ 的其他几个变体相比,在解决多模态问题方面的性能显着提高。 根据结果,在三个变体中,$CLPSO$ 是最好的。 因此,在文献[1]中进一步研究了 $CLPSO$。 16 | 17 | ### 2.1 综合学习策略 18 | 19 | 在 $CLPSO$ 中,主要特征就是广泛学习策略,该策略给予该算法更好的多模态求解能力,该策略改进的速度更新公式为: 20 | $$ 21 | v_i^d=\omega v_i^d+c*rand_i^d*(pBest_{f_i(d)}^d-x_i^d)\tag{1} 22 | $$ 23 | 24 | 从公式(1)来看,广泛学习策略的速度更新公式相较于经典粒子群优化算法缺少了全局最优对粒子的引导,只有一个 $pBest_{f_i(d)}^d$ 对粒子的引导。因此,理解 $pBest_{f_i(d)}^d$ 便是理解广泛学习策略甚至于 $CLPSO$ 的关键所在。 25 | 26 | 首先要明确的是,$pBest_{f_i(d)}^d$ 不是所更新速度粒子的历史最优的第 $i$ 个维度,而是根据相应法则从所有粒子的历史最优位置(包括自己)中挑选出来的。整体分为两个大部分: 27 | 28 | 在粒子 $i$ 速度的第 $d$ 维更新时是选择自己的 $pBest_i$ 的相应维度进行更新还是其他粒子的历史最优位置的相应维度。在该文中,作者通过一个随机概率 $Pc_i$ 来进行判定,判定的实施如下所示: 29 | $$ 30 | pBest_{f_i(d)}^d=\begin{cases} 31 | pBest_i^d; & if\quad rand_i^d>Pc_i\\ 32 | pBest_x^d; & otherwise 33 | \end{cases}\tag{2} 34 | $$ 35 | >在上式粒子$x$取值文中并未特别说明,一般来说取值范围为: $x=1,2,...,N;x\not ={i}$,但是对于这个取值范围约束产生的作用效果意义不大,而不排除当前粒子随机选择粒子相对于实现来说也更加方便。当然,约束取值版本可在code文件夹中获取。 36 | 37 | 即当产生的随机数大于概率 $Pc_i$ 时,则使用粒子自身的历史最优位置的第 $d$ 维 $pBest_i^d$ 进行更新,否则使用粒子 $X$ 的对应维度组合而成的新位置进行更新。从这个角度来看,规则除了写成公式(2)形式还可以写成公式(3)形式。 38 | $$ 39 | f_i(d)=\begin{cases} 40 | i,&if\quad rand_i^d>Pc_i\\ 41 | x,&otherwise 42 | \end{cases}\tag{3} 43 | $$ 44 | 此时公式(1)便可写成下式: 45 | $$ 46 | v_i^d=\omega v_i^d+c*rand_i^d*(pBest_i^d-x_i^d)\tag{4} 47 | $$ 48 | 49 | 当 $rand_i^d \not >Pc_i$ 时,也就是 $f_i(d)$ 取值为 $x$,而 $x$ 的取值还待确定,关于 $x$ 的确定,在文中作者提出了一种**竞技选择过程(Tournament Selection Procedure)** 50 | >在综合学习策略中,粒子会依概率去学习其他粒子对应维度信息。因此在算法初始化时,需要对每个维度都初始化一个学习概率$Pc$,写成向量的形式为:$\vec{Pc} = [pc_1,pc_2,\dotsb,pc_N]$,然后每次都会在对应维度生成一个随机数,再根据公式(2)与对应维度学习概率$Pc_i$进行比较,判断是否需要进行综合学习策略。 51 | 52 | ### 2.2 竞技选择过程 53 | 54 | >竞技过程并非和综合学习是同级别关系,竞技过程是综合学习策略中的一个过程,当粒子进入综合学习策略时,需要选择粒子$x$,这个时候就进入了竞技过程。 55 | 56 | 在粒子 $x$ 的选择上按照如下程序进行: 57 | 58 | 1. 首先随机在 $x$ 的取值范围内随机选择两个粒子的历史最优位置。即除却当前要更新速度的粒子之外的其他粒子的历史最优位置。 59 | 2. 在随机选择的两个粒子中比较两个粒子的历史最优位置的适应值,选择适应值更优越的历史最优位置作为此时的 $pBest_x^d$ ,以此进行速度的更新。此时更新公式可写成式(5)。 60 | 3. 当出现极端情况:某个粒子更新速度所有的维度都是使用的自身历史最优位置的对应维度进行更新,则随机选择一个维度来学习另一个粒子的历史最优对应维度。 61 | 62 | $$ 63 | v_i^d=\omega v_i^d+c*rand_i^d*(pBest_x^d-x_i^d)\tag{5} 64 | $$ 65 | 66 | >这里稍微进行补充: 67 | > 68 | >- 第一点:我们在进行函数求解时,适应值一般是用是否更优越来描述,而不是大小描述,这是由于对于求解的问题不一样,评判标准不一样。当求解函数最大值时,则适应度越大越优越;当求解的问题是求解最小值时,适应度越小越优越。因此在以往的描述中,一般都是使用适应值的优越程度,而不使用适应值大小之类的描述,以免造成误解。 69 | >- 第二点:上面第三个过程在文献[1]中并未提及如何选择另一个粒子,这里就暂定从除更新粒子外的其他粒子中的随机选择一个粒子。 70 | 71 | ![ref](images/CLPSO-1.jpg) 72 | 73 | >上图是作者论文中描述的竞技选择过程流程图,但是在其中存在一个问题,那便是对论文中第三个要点图中并未体现,也并未注明。由此,图与文便产生了冲突。具体如何处理,我会在最后进行相关性说明。 74 | 75 | ### 2.3 CLPSO 与 经典 PSO 区别 76 | 77 | 在作者的实验过程中,发现了 CLPSO 与 经典 PSO 有三个主要区别: 78 | 79 | 1. 经典PSO的粒子学习对象来自自身历史最优位置及全局历史最优。在CLPSO中任意一个粒子的历史最优位置都有可能成为学习对象,引导粒子的飞行方向。 80 | 2. 与从所有维度的相同粒子的 $pBest$ 学习的经典 $PSO$ 不同,粒子的每个维度通常可以从一代甚至于几代相同维度的不同 $pBest$ 中学习。 换句话说,一个粒子的每个维度都可以从不同粒子的 $pBest$ 的对应维度中学习。 81 | 3. 与经典 $PSO$ 中的每一代同时从两个样本($pBest$ 和 $gBest$)学习不同,$CLPSO$ 粒子的每个维度只从一个样本学习几代。 82 | 83 | ### 2.4 CLPSO 的搜索行为 84 | 85 | 在文献[1]中,作者提出广泛学习策略能够增加种群的多样性,同时能提高算法在多模态(多峰)问题的求解能力。 86 | 此外提出经典 $PSO$ 存在振荡问题。具体描述如下图: 87 | ![ref](images/CLPSO-2.jpg) 88 | 89 | 其主要出发点在于当多个历史最优值在同一维度线上,或者直接看成上图的直线,且粒子在 $pBest$ 和 $gBest$ 中间,那么该粒子在迭代更新时便会受到左右两边的历史最优的同时拉扯,从而出现振荡现象。 90 | >下面仅为个人观点:个人觉得振荡有更大的可能发生在 $CLPSO$ 中,而非经典 $PSO$ ,正如文献[1]提供的图,有两者在中间拉扯,但是在每次运行中历史最优都会被更新,倘若该粒子这次被 $gBest$ 拉扯到偏向 $gBest$ 位置,如果该位置优于该粒子的历史最优位置,那么就会更新。所以虽然可能出现在中间的情形,但一定会偏向一边移动。而由于 $CLPSO$ 只有一个学习对象 $pBest_{f_i(d)}^d$,当这个学习对象在广泛学习过程中得到的位置在整体上总是劣与该粒子,那么就会出现该粒子一直在比当前粒子历史最优更差的区域不停的游荡。 91 | 92 | 作者还提出,即使在远离全局最优的局部最优区域中,$gbest$ 也可能影响粒子沿其方向移动。 如果 $pbest$ 和 $gbest$ 在粒子当前位置的同一侧,并且指向局部最优,则粒子将朝那个方向移动,一旦 $pbest$ 落入相同的位置,粒子可能无法跳出局部最优区域。 $gbest$ 所在的局部最优区域。然而,在广泛学习策略中,当粒子的 $pbest$ 和 $gbest$ 落入相同的局部最优区域时,粒子可以通过学习其他粒子的 $pbest$ 向其他方向飞行。 因此,广泛学习策略能够通过整个群体的合作行为跳出局部最优。 93 | 94 | ### 2.5 学习概率 $Pc_i$ 95 | 96 | 由于在文献 [2] 的测试中中,作者发现如果对群体中的所有粒子使用相同的 $Pc$ 值,不同的 $Pc$ 值会在同一问题上产生不同的结果。 在非旋转的问题上,较小的值表现更好,而在旋转的问题上,不同的 $Pc$ 对不同的问题产生最佳性能。 不同的 $Pc$ 值在简单的单峰问题上产生相似的结果,同时严重影响 $CLPSO$ 在多峰问题上的性能。 97 | 98 | >至于该文对旋转及非旋转问题的定义文中未能提及,本人才疏学浅,无力解释,便对该问题不多言。但是这个问题对算法的理解与实现是没有关系的。 99 | 100 | 因此,作者提出对不同的粒子生成不同的概率值 $Pc$,计算公式如下: 101 | $$ 102 | Pc_i=0.05+0.45*\frac{e^\frac{10(i-1)-1}{N-1}-1}{e^{10}-1}\tag{6} 103 | $$ 104 | 根据公式可知 $Pc_i$ 的取值范围为 $[0.05,0.5]$。 105 | 106 | ### 2.6 边界处理 107 | 108 | 在 $CLPSO$ ,边界处理的方式与一般边界处理的方式一致,在文献[1]中作者写为:$V_i^d=min(V_{max}^d,max(V_{min}^d,V_i^d))$,这个公式其实可以写成更简单易懂的形式,如下公式(7)所示: 109 | $$ 110 | V_i^d=\begin{cases} 111 | V_{max}^d,&if\quad V_i^d>V_{max}^d\\ 112 | V_{min}^d,&if\quad V_i^d 在该文中,对于位置越界的情况并未进行边界处理。 117 | 118 | ### 2.7 刷新间隔 119 | 120 | 在 $CLPSO$ 中,当出现特殊情况,例如某个粒子的历史最优值长时间未能得到更新,即未能找到更优越的位置,$CLPSO$ 会使用经典 $PSO$ 算法中速度更新公式进行速度更新。在 $CLPSO$ 中,作者设置刷新间隔 $m=7$。 121 | 122 | ## 3 算法实现 123 | 124 | 算法的整体代码编写依照算法流程图! 125 | 126 | $CLPSO$ 算法的整体流程如下: 127 | ![ref](images/CLPSO-4.jpg) 128 | >在上面的流程图中,速度更新时的判断出现了错误,这里使用在上文分析的方法。同时图中计算惯性权重公式是有问题的,应该是少了一个减号,真正的惯性权重计算公式应为: 129 | $$ 130 | \omega = \omega_0-(\omega_0-\omega_1)*\frac{iterate}{MaxIterate}\tag{8} 131 | $$ 132 | 其中 $iterate$ 是当前迭代次数,$MaxIterate$ 是指最大迭代次数。 133 | 134 | 当 $flag\geq m$,则执行图中的步骤一,即经典 $PSO$ 速度更新方式,如下图所示。 135 | ![ref](images/CLPSO-3.jpg) 136 | 整体流程到此结束。 137 | 138 | ## 4 写在后面 139 | 140 | 鉴于我对文献[1]某些地方理解存在偏差,为了更加严谨的实现代码,我写了三个不同版本的 $CLPSO$ 版本。 141 | 142 | - 版本一:按照流程图的方式书写代码。在该代码中,没有第三个要点,即当粒子的所有维度都没有满足 $rand_i^d- 从实验结果来看,三者之间的差别并不是很大。当然各位也可以进行编写测试,或者可直接使用我的代码。 147 | 148 | 代码详情见code文件夹 149 | 150 | ## 5 文献参考 151 | 152 | [1] Liang J J , Qin A K , Suganthan P N , et al. Comprehensive learning particle swarm optimizer for global optimization of multimodal functions[J]. IEEE Transactions on Evolutionary Computation, 2006, 10(3):281-295. 153 | [2] Liang J J , Qin A K , Suganthan P M , et al. Particle swarm optimization algorithms with novel learning strategies[C]// IEEE International Conference on Systems. IEEE, 2004. 154 | -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/code/matlab/FunAPSO.m: -------------------------------------------------------------------------------- 1 | %% =============================================================================%% 2 | %% 自适应粒子群优化 3 | % coding:陈小斌 4 | % Github:doFighter 5 | % N:种群大小 6 | % dim:问题的维度 7 | % x_max:解空间的上界 8 | % x_min:解空间的下界 9 | % iterate_max:最大迭代次数 10 | % fitness:测试函数 11 | %% -----------------------------------------------------------------------------%% 12 | function [rest] = FunAPSO(N,dim,x_max,x_min,iterate_max,fitness) 13 | c = 2*ones(1,2); % 加速系数 c1,c2 14 | fitness_value = ones(N,1); % 对应粒子的适应度值 15 | curState = 1; % 当前状态(阶段) 初始化时都为1 16 | lastState = 1; % 上一状态(阶段) 17 | gBest_result = ones(iterate_max,1); % 存放吗,每次迭代最优的适应度值 18 | 19 | 20 | v_min = 0.2*x_min; % 速度的下限,取解的范围的20% 21 | v_max = 0.2*x_max; % 速度的上限 22 | x = x_min + (x_max - x_min)*rand(N,dim); % 初始化粒子的位置 23 | v = v_min + (v_max - v_min)*rand(N,dim); % 初始化粒子的速度 24 | pBest = x; % 初始化 pBest,此时 pBest 为其本身 25 | % 初始化 gBest 26 | curBest_index = 1; % 全局最优粒子位置下标 27 | gWorst_index = 1; % 全局最差粒子位置下标 28 | fitness_value(1) = fitness(x(1,:)); 29 | for i=2:N 30 | fitness_value(i) = fitness(x(i,:)); 31 | if fitness(x(curBest_index,:)) > fitness_value(i) 32 | curBest_index = i; 33 | end 34 | if fitness(x(gWorst_index,:)) < fitness_value(i) 35 | gWorst_index = i; 36 | end 37 | end 38 | gBest = x(curBest_index,:); 39 | 40 | iterate = 1; % 由于 matlab 数组下标从 1 开始,为了方便后期处理,迭代次数的下标也从 1 开始 41 | % 迭代停止条件可以是到达某个可接受的精度或者是指定的迭代次数,这里使用指定迭代次数 42 | while iterate < iterate_max + 1 43 | gBest_result(iterate) = fitness(gBest); 44 | 45 | % 进化状态评估 46 | [w,c,lastState,gBest,pBest,x] = Evolutionary_States_Estimation(c,fitness,N,curBest_index,curState,lastState,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index); 47 | v = w*v + c(1)*rand(N,dim).*(pBest - x) + c(2)*rand(N,dim).*(gBest - x); 48 | 49 | % 对超出速度上下限的粒子进行速度矫正 50 | v(vv_max) = v_max; 52 | x = x + v; % 速度更新 53 | 54 | % 对粒子位置超出界限的粒子在 all_in_range 数组中标记为否,也就是置为 0 55 | [r,~] = find(x>x_max|x fitness(pBest(gWorst_index,:)) 74 | gWorst_index = i; 75 | end 76 | end 77 | iterate = iterate + 1; 78 | end 79 | rest = fitness(gBest); 80 | end 81 | 82 | 83 | 84 | % 进化状态评估函数 85 | function [w,c,lastState,gBest,pBest,x] = Evolutionary_States_Estimation(c,fitness,N,curBest_index,curState,lastState,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index) 86 | distance = zeros(N,1); 87 | for i=1:N 88 | sum_d = sum(((x(i,:) - x).^2),2); % 粒子i与各粒子的距离平方和 89 | distance(i) = sum(sum_d.^0.5)/(N - 1); % 粒子 i 的平均距离 90 | end 91 | d_g = distance(curBest_index); % 全局最优粒子的平均距离 92 | d_max = max(distance); % 粒子群中最大的平均距离 93 | d_min= min(distance); % 粒子群中最小的平均距离 94 | 95 | % 计算进化因子 96 | if d_min == d_max 97 | f = 1; 98 | else 99 | f = (d_g - d_min)/(d_max - d_min); 100 | end 101 | 102 | % 根据进化因子判断进化状态并执行相对应的操作 103 | [w,c,lastState,gBest,pBest,x] = Adaptive_Parameters(c,fitness,f, curState, lastState,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index); 104 | end 105 | 106 | 107 | 108 | % 自适应选择调整函数 109 | function [w,c,lastState,gBest,pBest,x] = Adaptive_Parameters(c,fitness,f, curState, lastState,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index) 110 | w = 1/(1 + 1.5*exp(-2.6*f)); 111 | if f<=0.2 % 汇聚 112 | c = Adaptive_C(c,0.5,0.5); 113 | [gBest,pBest,x] = Elitist_learning(fitness,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index); 114 | curState=3; 115 | elseif f<=0.3 % 模糊逻辑区域 116 | if lastState==3||lastState==4 % 汇聚 117 | c = Adaptive_C(c,0.5,0.5); 118 | [gBest,pBest,x] = Elitist_learning(fitness,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index); 119 | curState=3; 120 | elseif lastState==2||lastState==1 %开发 121 | c = Adaptive_C(c,0.5,-0.5); 122 | curState=2; 123 | end 124 | elseif f<=0.4 %开发 125 | c = Adaptive_C(c,0.5,-0.5); 126 | curState=2; 127 | elseif f<=0.6 %模糊逻辑区域 128 | if lastState==2||lastState==3 %开发 129 | c = Adaptive_C(c,0.5,-0.5); 130 | curState=2; 131 | elseif lastState==1||lastState==4 %勘探 132 | c = Adaptive_C(c,1.0,-1.0); 133 | curState=1; 134 | end 135 | elseif f<=0.7 %勘探 136 | c = Adaptive_C(c,1.0,-1.0); 137 | curState=1; 138 | elseif f<=0.8 %模糊逻辑区域 139 | if lastState==1||lastState==2 %勘探 140 | c = Adaptive_C(c,1.0,-1.0); 141 | curState=1; 142 | elseif lastState==4||lastState==3 %跳出 143 | c = Adaptive_C(c,-1.0,1.0); 144 | curState=4; 145 | end 146 | else %跳出 147 | c = Adaptive_C(c,-1.0,1.0); 148 | curState=4; 149 | end 150 | lastState=curState; 151 | end 152 | 153 | 154 | % 调整加速系数函数 155 | function [c] = Adaptive_C(c,h1,h2) 156 | c(1) = c(1) + h1*(0.05 + 0.05*rand); % (0.05 + 0.05*rand) 生成[0.05,0.1]之间的随机数 157 | c(2) = c(2) + h2*(0.05 + 0.05*rand); 158 | c(c>2.5) = 2.5; 159 | c(c<1.5) = 1.5; 160 | sum_c = sum(c); 161 | % 归一化操作 162 | if sum_c < 3 163 | c = (c.*3)/sum_c; 164 | elseif sum_c > 4 165 | c = (c.*4)/sum_c; 166 | end 167 | end 168 | 169 | % 精英学习策略 170 | function [gBest,pBest,x] = Elitist_learning(fitness,pBest, gBest, dim, x_max, x_min, iterate, iterate_max, x, gWorst_index) 171 | mu = 0; 172 | sigma_max = 1; 173 | sigma_min = 0.1; 174 | sigma = sigma_max - (sigma_max - sigma_min)*iterate/iterate_max; 175 | p = gBest; 176 | d = 1 + round(rand*(dim - 1)); % 随机选择一个维度进行扰动 [1,dim] 177 | p(d) = p(d) + (x_max - x_min)*normrnd(mu,sigma); % normrnd(mu,sigma) 正态分布函数 178 | % 判断扰动过后是否超出范围,若超出,则在解的范围内随机取值 179 | if p(d) > x_max || p(d) < x_min 180 | p(d) = x_min + (x_max - x_min)*rand; 181 | end 182 | p_value = fitness(p); 183 | if p_value < fitness(gBest) 184 | gBest = p; 185 | else 186 | if p_value < fitness(pBest(gWorst_index,:)) 187 | pBest(gWorst_index,:) = p; 188 | x(gWorst_index,:) = p; 189 | else 190 | x(gWorst_index,:) = p; 191 | end 192 | end 193 | 194 | end 195 | 196 | % gaussian 函数编写 197 | % 可直接使用 matlab 提供的 gaussian 随机生成函数,测试效果一样 198 | 199 | % function [res] = gaussian(mu,sigma) 200 | % u1 = rand; 201 | % u2 = rand; 202 | % x=sqrt(-2.0*log(u1))*cos(2.0*pi*u2); 203 | % res = sigma*x+mu; 204 | % end 205 | 206 | -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-1.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-2.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-3.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-4.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-5.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-6.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-7.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-8.png -------------------------------------------------------------------------------- /粒子群优化算法/自适应粒子群优化/images/APSO-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/粒子群优化算法/自适应粒子群优化/images/APSO-9.png -------------------------------------------------------------------------------- /萤火虫算法/萤火虫优化FA/code/matlab/FA.m: -------------------------------------------------------------------------------- 1 | %% =============================================================================%% 2 | %% FA:萤火虫算法(DOI: 10.1007/978-3-642-04944-6_14) 3 | % coding:陈小斌 4 | % Encoding format:utf-8 5 | % :param N: 种群数目 6 | % :param dim: 求解维度 7 | % :param x_min: 各维度搜索下限 8 | % :param x_max: 各维度搜索上限 9 | % :param iterate_max: 最大迭代次数 10 | % :param fitness: 适应度评价函数 11 | % :return: 12 | % optimal_value: 对应评价函数最优适应度 13 | % optimal_site: 最优位置 14 | %% -----------------------------------------------------------------------------%% 15 | 16 | function [optimal_value, optimal_site] = FA(N, dim, x_min, x_max, iterate_max, fitness) 17 | % 初始化位置 18 | x = x_min + (x_max - x_min) * rand(N, dim); 19 | % 计算各位置的适应度值 I 20 | I = ones(N, 1); 21 | for i = 1:N 22 | I(i) = fitness(x(i, :)); 23 | end 24 | 25 | % 对萤火虫按照适应度进行排序 26 | [~, I_range_index] = sort(I); 27 | % 定义灯光吸收系数 28 | % gamma = 1/(dim ** 2); 29 | gamma = 1; 30 | % 引力系数值 31 | beta0 = 1; 32 | % 初始化 alpha 33 | alpha = 0.2; 34 | 35 | % 迭代计数器 36 | iterate = 1; 37 | 38 | while iterate < iterate_max + 1 39 | for i = 1:N 40 | for j = 1:i 41 | % 如果前面的优于后面的,则往对应位置移动 42 | if I(I_range_index(j)) < I(I_range_index(i)) 43 | r_ij = sum((x(I_range_index(i), :) - x(I_range_index(j), :)) .^ 2); 44 | x(I_range_index(i), :) = x(I_range_index(i), :) +beta0 * exp(-gamma * r_ij) .* (x(I_range_index(j), :) - x(I_range_index(i), :)) + alpha .* (rand(1, dim) - 0.5); 45 | % 更新第i只萤火虫的解 46 | I(I_range_index(i)) = fitness(x(I_range_index(i), :)); 47 | end 48 | end 49 | end 50 | % 对萤火虫按照适应度进行排序 51 | [~, I_range_index] = sort(I); 52 | 53 | iterate = iterate + 1; 54 | end 55 | 56 | optimal_value = I(I_range_index(1)); 57 | optimal_site = x(I_range_index(1), :); 58 | end -------------------------------------------------------------------------------- /萤火虫算法/萤火虫优化FA/code/python/FA.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2022/1/14 14:06 4 | # @Author : 陈小斌 5 | # @Github : doFighter 6 | # @File : FA.py 7 | # @Software: PyCharm 8 | 9 | import numpy as np 10 | 11 | 12 | def FA(N, dim, x_min, x_max, iterate_max, fitness): 13 | """ 14 | FA:萤火虫算法 DOI: 10.1007/978-3-642-04944-6_14 15 | :param N: 种群数目 16 | :param dim: 求解维度 17 | :param x_min: 各维度搜索下限 18 | :param x_max: 各维度搜索上限 19 | :param iterate_max: 最大迭代次数 20 | :param fitness: 适应度评价函数 21 | :return: 22 | I[I_range_index[0]]: 对应评价函数最优适应度 23 | x[I_range_index[0], :]: 最优位置 24 | """ 25 | # 初始化位置 26 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 27 | # 计算各位置的适应度值 I 28 | I = np.ones([N, 1]) 29 | for i in range(N): 30 | I[i] = fitness(x[i, :]) 31 | # 对萤火虫按照适应度进行排序 32 | range_list = sorted(enumerate(I), key=lambda I_zip: I_zip[1]) 33 | I_range_index = [ele[0] for ele in range_list] 34 | # 定义灯光吸收系数 35 | # gamma = 1/(dim ** 2) 36 | gamma = 1 37 | # 初始化 alpha 38 | alpha = 0.2 39 | 40 | # 迭代计数器 41 | iterate = 0 42 | 43 | while iterate < iterate_max: 44 | for i in range(N): 45 | for j in range(i): 46 | # 如果前面的优于后面的,则往对应位置移动 47 | if I[I_range_index[j]] < I[I_range_index[i]]: 48 | r_ij = sum((x[I_range_index[i], :] - x[I_range_index[j], :]) ** 2) 49 | x[I_range_index[i], :] = x[I_range_index[i], :] + np.exp(-gamma * r_ij) * (x[I_range_index[j], :] - x[I_range_index[i], :]) + alpha * (np.random.rand(dim) - 0.5) 50 | # 更新第i只萤火虫的解 51 | I[I_range_index[i]] = fitness(x[I_range_index[i], :]) 52 | 53 | # 对萤火虫按照适应度进行排序 54 | range_list = sorted(enumerate(I), key=lambda I_zip: I_zip[1]) 55 | I_range_index = [ele[0] for ele in range_list] 56 | 57 | iterate = iterate + 1 58 | return I[I_range_index[0]], x[I_range_index[0], :] 59 | 60 | 61 | def Sphere(xx): 62 | """ 63 | Sphere Function 64 | :param xx: 疑似最优解 65 | :return:适应度值 66 | """ 67 | d = len(xx) 68 | sum = 0 69 | for i in range(d): 70 | sum += xx[i] ** 2 71 | return sum 72 | 73 | 74 | # 函数测试 75 | for i in range(3): 76 | result, site = FA(20, 30, -10, 10, 1000, Sphere) 77 | print(result) 78 | print(site) 79 | -------------------------------------------------------------------------------- /萤火虫算法/萤火虫优化FA/images/FA-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/萤火虫算法/萤火虫优化FA/images/FA-1.png -------------------------------------------------------------------------------- /萤火虫算法/萤火虫优化FA/萤火虫算法.md: -------------------------------------------------------------------------------- 1 | # 萤火虫算法(Firefly Algorithm,FA) 2 | 3 | ## 1 引言 4 | 5 | 在热带和温带地区的夏日天空中,萤火虫闪烁的光芒是令人惊叹的景象。大约有两千种萤火虫,大多数萤火虫会产生短暂而有节奏的闪光。对于特定物种,闪光的模式通常是独一无二的。闪光是由生物发光过程产生的,这种信号系统的真正功能仍在争论中。然而,这种闪光的两个基本功能是吸引交配伙伴(交流)和吸引潜在的猎物。此外,闪烁也可以作为一种保护警告机制。有节奏的闪光、闪光的速度和时间量构成了将两性结合在一起的信号系统的一部分。雌性萤火虫会对同一物种中雄性独特的闪光模式作出反应,而在某些物种中,例如萤火虫,雌性萤火虫可以模仿其他物种的交配闪光模式,以引诱和吃掉可能将闪光误认为潜在的雄性萤火虫合适的伴侣。 6 | 7 | 在距光源特定距离 $r$ 处的光强服从平方反比定律。 也就是说,根据 $I ∝ 1/r_2$ ,光强度 $I$ 随着距离 $r$ 的增加而减小。 此外,空气吸收的光随着距离的增加而变得越来越弱。 这两个综合因素使大多数萤火虫只能在有限的距离内可见,通常在夜间数百米,这通常足以让萤火虫进行交流。 闪光灯可以与要优化的目标函数相关联的方式来制定,这使得制定新的优化算法成为可能。 8 | 9 | >$∝$符号表示两者成正比例关系 10 | 11 | ## 2 算法介绍 12 | 13 | 论文将萤火虫的一些闪烁特性理想化,从而开发出萤火虫启发的算法。 为了简单描述我们的新萤火虫算法($FA$),现使用以下三个理想化规则: 14 | 15 | - 1. 所有萤火虫都是雌雄皆宜的,因此无论性别如何,一只萤火虫都会被其他萤火虫吸引; 16 | - 2. 吸引力与它们的亮度成正比,因此对于任何两只闪烁的萤火虫,较不亮的一只会向较亮的一只移动。 吸引力与亮度成正比,并且它们都随着距离的增加而减小。 如果没有比特定萤火虫更亮的萤火虫,它会随机移动; 17 | - 3. 萤火虫的亮度受目标函数的模型影响或决定。 对于最大化问题,亮度可以简单地与目标函数的值成正比。 其他形式的亮度可以以类似于遗传算法中的适应度函数的方式定义。 18 | 19 | 基于这三个规则,萤火虫算法(FA)的基本步骤可以概括为图1所示的伪代码。 20 | 21 | ![ref](images/FA-1.png) 22 | 23 | 在 $FA$ 中,吸引力与它们的目标函数和吸引力随距离的单调衰减有关。 然而,$FA$ 中的智能体具有可调节的可见性和更多的吸引力变化,这通常会导致更高的移动性,因此可以更有效地探索搜索空间。 24 | 25 | ### 2.1 吸引力 26 | 27 | 在萤火虫算法中,有两个重要的问题: 28 | 29 | - 光强的变化 30 | - 吸引力的制定 31 | 32 | 为简单起见,文中假设萤火虫的吸引力取决于它的亮度,而亮度又与编码的目标函数相关联。在最大优化问题的最简单情况下,亮度 $I$ 33 | 特定位置 $x$ 的萤火虫可以选择 $I(x) ∝ f(x)$。但是,吸引力$β$是相对的,应该在旁观者眼中看到或由其他萤火虫判断。因此,它会随着萤火虫 $i$ 和萤火虫 $j$ 之间的距离 $r_{ij}$ 而变化。另外,光强度随着离光源的距离而减小,光也在介质中被吸收,所以我们应该允许吸引力随着吸收的程度而变化。在最简单的形式中,光强度 $I(r)$ 根据平方反比定律 $I(r)= I_s/r^2$ 变化,其中 $I_s$ 是光源处的强度。对于给定光吸收系数$γ$固定的介质,光强$I$随着距离$r$的变化而变化。即$I=I_0e^{-γr}$,其中$I_0$为原始光强。为了避免表达式 $I_s/r^2$ 中 $r = 0$ 处的奇异性,平方反比定律和吸收的组合效应可以使用以下高斯形式来近似: 34 | 35 | $$ 36 | I(r)=I_0e^{-γr^2}\tag{1} 37 | $$ 38 | 39 | 有时,可能需要一个以较慢速率单调递减的函数。 在这种情况下,可以使用以下近似: 40 | 41 | $$ 42 | I(r)=\frac{I_0}{1+γr^2}\tag{2} 43 | $$ 44 | 45 | 在较短的距离上,上述两种形式基本相同。 这是因为关于 $r = 0$ 的级数展开在 $O(r^3)$ 的数量级上彼此等价。 46 | 47 | $$ 48 | \begin{cases} 49 | e^{-γr^2}=1--γr^2+\frac{1}{2}γ^2r^4\\ 50 | \frac{1}{1+γr^2}=1--γr^2+\frac{1}{2}γ^2r^4\\ 51 | \end{cases}\tag{3} 52 | $$ 53 | 54 | 由于萤火虫的吸引力与相邻萤火虫看到的光强度成正比,我们现在可以定义萤火虫的吸引力$β$为: 55 | 56 | $$ 57 | β(r)=β_0e^{-γr^2}\tag{4} 58 | $$ 59 | 60 | >其中 $β_0$ 是 $r = 0$ 时的吸引力。由于计算 $1/(1+r^2)$ 通常比指数函数更快,因此如果需要,上述函数可以方便地替换为 $β=\frac{β_0}{1+γr^2}$。等式 (4) 定义了一个特征吸引力从 $β_0$ 到 $β_0e^{-1}$ 显著变化的距离 $\Gamma=1/\sqrt{γ}$。 61 | 62 | 在实现中,吸引力函数$β(r)$的实际形式可以是任何单调递减函数,例如以下广义形式: 63 | 64 | $$ 65 | β(r)=β_0e^{-γr^m},\;(m\geq1) \tag{5} 66 | $$ 67 | 68 | 对于固定的 $γ$,当$m →∞$特征长度变为 $Γ = γ^{−1/m} → 1$。 相反,对于优化问题中给定的长度尺度$Γ$,参数$γ$可以用作典型的初始值。 即$γ=\frac{1}{Γ^m}$。 69 | 70 | ### 2.2 距离和运动 71 | 72 | 任意两个萤火虫 $i$ 和 $j$ 分别在 $x_i$ 和 $x_j$ 处的距离是笛卡尔距离: 73 | 74 | $$ 75 | r_{ij}=||X_i-X_j||=\sqrt{\sum_{k=1}^d(x_{i,k}-x_{j,k})^2}\tag{6} 76 | $$ 77 | 78 | >其中 $x_{i,k}$ 是第 $i$ 个萤火虫的空间坐标 $x_i$ 的第 $k$ 个分量。 在二维情况下,我们有 $r_{ij}=\sqrt{(x_i-x_j)^2+(y_i-y_j)^2}$。 79 | 80 | 萤火虫 $i$ 的运动被另一个更有吸引力(更亮)的萤火虫 $j$ 吸引,由下式决定: 81 | 82 | $$ 83 | X_i=X_i+β_0e^{-γr_{ij}^2}(X_j-X_i)+\alpha(rand-\frac{1}{2})\tag{7} 84 | $$ 85 | 86 | >其中第二项是由于吸引力,而第三项是随机化,α是随机化参数。 rand 是均匀分布在 [0, 1] 中的随机数生成器。 87 | 88 | 对于作者实现中的大多数情况,可以取 $β_0 =1$ 和 $α ∈ [0, 1]$。此外,随机化项可以很容易地扩展到正态分布 $N(0, 1)$ 或其他分布。此外,如果尺度在不同维度上变化很大,例如一个维度为 -105 到 105,而另一个维度为 -0.001 到 0.01,则将 $α$ 替换为 $αS_k$ 是一个好主意,其中缩放参数 $S_k(k = 1, ..., d)$中的$d$维应由感兴趣问题的实际尺度确定。参数 $γ$ 现在表征了吸引力的变化,它的值对于确定收敛速度和 $FA$ 算法的行为至关重要。理论上,$γ ∈ [0,∞)$,但在实践中,$γ = O(1)$ 由待优化系统的特征长度 $Γ$ 决定。因此,在大多数应用中,它通常在 0.01 到 100 之间变化。 89 | 90 | ## 3 算法实现 91 | 92 | **参数设置:** 93 | 94 | - $α=0.2$ 95 | - $γ=1$ 96 | - $β0=1$ 97 | 98 | 算法实现中有以下要点注意: 99 | 100 | - 要点一 101 | 102 | 文献中给出了灯光吸引系数$\gamma$具体计算,该值与优化模型的特征长度有关,即问题求解维度$d$。 103 | 104 | 但是在测试中,给定的是一个具体值$γ=1$ 105 | 106 | 此外,作者给出:$γ=\frac{1}{Γ^m}$,即灯光吸引系数$\gamma$与特征长度的关系,特征长度肯定是大于1的,因此根据该公式,$\gamma$的取值范围应该在$[1,0)$之间,而非$[0.01,100]$。 107 | 108 | 最后,对于$\gamma$中给出求解公式中的$m$作者并未给出具体值。 109 | 110 | >在本人的代码实现过程中,取值为2。 111 | 112 | - 要点二 113 | 114 | 在论文中,作者给出的位置更新公式(7)中使用的是$\beta_0$,即一个常数,但是在算法框架中,又说吸引力要随着粒子距离$r_{ij}$不断更新。 115 | 116 | >在这里可能会进入误区,在后面的公式(7)位置更新中,作者是显式的将吸引力$beta$写进去了,因为吸引力$beta$求解公式(4)即为位置更新公式(7)中的一部分。 117 | 118 | - 要点三 119 | 120 | 公式(7)看似是一个向量公式,因为在描述当中是使用的是第$i$只萤火虫位置,因此是一个向量。但是根据测试效果来判断,公式中的$rand$是基于维度级别的,即公式(7)可以写成: 121 | 122 | $$ 123 | X_{i,d}=X_{i,d}+β_0e^{-γr_{ij}^2}(X_{j,d}-X_{i,d})+\alpha(rand-\frac{1}{2})\tag{8} 124 | $$ 125 | 126 | 使用上述公式(8)算法效果要远远优于公式(7)。 127 | 128 | >上面两个公式极其相似,不同之处就在于随机数$rand$,在公式(8)中,每个维度的随机数都是重新生成的,即不同维度随机数都是不同的。 129 | 130 | - 要点四 131 | 132 | 在参考文献的算法伪代码框架中,在更新位置之后要更新对应位置的适应度值,,并将萤火虫按照适应度进行排序。 133 | 因此,在算法中,每只适应度好于当前适应度的萤火虫都会对后面的萤火虫进行引导。 134 | 135 | > 1. 按照这种方式,在一开始初始化位置并计算对应位置的适应度值之后也应该对其进行排序,在文献算法伪代码中没有明确说明。 136 | > 2. 如果是这样的话,那么在前面的萤火虫适应度应该就肯定优于当前萤火虫,那$if$条件判断能否去除呢?这个个人觉得对于结果的影响不会很大,但是该语句的存在可以避免适应度相同的萤火虫相互吸引。(当然,适应度相同的萤火虫相互吸引也不一定是一件坏事。) 137 | 138 | - 最后,根据原论文的思路,效果并不理想 139 | 140 | ## 4 参考文献 141 | 142 | [1]Yang X S. Firefly algorithms for multimodal optimization[C]//International symposium on stochastic algorithms. Springer, Berlin, Heidelberg, 2009: 169-178. 143 | -------------------------------------------------------------------------------- /蚁群优化算法/一种改进的自适应蚁群算法/images/IAACO-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/蚁群优化算法/一种改进的自适应蚁群算法/images/IAACO-1.jpg -------------------------------------------------------------------------------- /蚁群优化算法/一种改进的自适应蚁群算法/一种改进的自适应蚁群算法.md: -------------------------------------------------------------------------------- 1 | # 一种改进的自适应蚁群算法 2 | 3 | ## 1 引言 4 | 5 | 针对传统蚁群算法(ACO)在室内移动机器人路径规划中路径规划时间长、收敛速度慢、非最优路径、ACO局部最优解等缺点,提出一种改进的自适应算法。本文提出了蚁群算法(IAACO)。在IAACO中,首先为了加快机器人路径规划的实时性和安全性,在ACO的转移概率中引入了角度引导因子和障碍物排除因子;其次,在ACO的信息素更新规则中引入启发式信息自适应调整因子和自适应信息素挥发因子,平衡ACO的收敛性和全局搜索能力;最后,引入多目标性能指标,将路径规划问题转化为多目标优化问题,实现机器人路径规划的全面全局优化。主要参数选择、不同环境下路径规划性能、最优解多样性的实验结果表明,IAACO可以使机器人获得全局优化路径,路径规划具有较高的实时性和稳定性。 6 | 7 | ## 2 主要内容 8 | 9 | 1. 改进了传统蚁群算法(ACO)中的启发式信息、状态转移概率、信息素更新规则,平衡了算法的全局搜索能力和收敛速度,使机器人更好地达到路径回避能力和路径搜索效率。 10 | 2. 综合考虑路径长度、安全性和能耗指标,将路径规划问题转化为多目标优化问题,使机器人获得综合全局最优路径。 11 | 3. 基于改进的主要参数、改进的ACO更新规则和多目标路径规划优化,提出了基于IAACO的路径规划过程并通过实验验证。 12 | 13 | 本文主要着重于算法的实现,因此对于网格环境建模、 ACO 的路径规划等问题不进行详细描述。 14 | 15 | ## 3 一种改进的自适应蚁群算法(IAACO) 16 | 17 | ### 3.1 改进启发式信息 18 | 19 | 在 $ACO$ 中,由于启发式信息只考虑当前网格与待选择网格的距离,会导致算法早期全局性能不佳。 为了提高搜索的启发性,还考虑了所选网格与目标网格之间的距离。此外,在算法后期,为了削弱启发式信息的作用,平衡算法的全局搜索能力和收敛速度,引入了自适应调整因子。 20 | 21 | 因此,改进启发式信息为: 22 | 23 | $$ 24 | \eta_{ij}(t)=\varepsilon(\frac{1}{\sigma_1d_{ij}+\sigma_2d_{jG}})\tag{1} 25 | $$ 26 | 27 | >其中 $d_{ij}$ 是第 $i$ 个网格与第 $j$ 个网格之间的距离; $d_{jG}$ 为待选第 $j$ 个网格与目标网格 $G$ 的距离;$σ_1$ 和 $σ_2$ 为距离权重系数,$σ_1+σ_2=1$; 自适应调整因子 $ε$ 是变形的正态分布函数。 在算法前期,由于 $ε$ 接近 1,可以加强启发式信息的作用,从而加快算法的收敛速度; 后期由于 $ε$ 远小于 1,可以削弱启发式信息的作用,从而增强算法的全局搜索能力。 $ε$ 的计算如公式(2)所示。 28 | 29 | $$ 30 | \varepsilon=e^{-2(\frac{N_c}{N_{max}})^2}\tag{2} 31 | $$ 32 | 33 | >其中 $N_C$ 是当前迭代次数,$N_{max}$ 是最大迭代次数。 34 | 35 | ### 3.2 改进状态转移概率 36 | 37 | 针对移动机器人的路径规划,为了获得安全高效的无障碍路径,提高路径搜索效率,文中在 $ACO$ 的传递概率中引入障碍排除因子和角度引导因子,从而增加路径搜索的多样性,提高路径规避能力和搜索效率。 38 | 39 | 改进转移概率如等式(3)所示: 40 | 41 | $$ 42 | P_{ij}^k(t)=\begin{cases} 43 | \frac{[\tau_{ij}(t)]^\alpha [\eta_{ij}(t)]^\beta[\mu_{ij}(t)]^\lambda[\xi_{ib}(t)]}{\sum_{s\in allowed_k}[\tau_{is}(t)]^\alpha [\eta_{is}(t)]^\beta[\mu_{is}(t)]^\lambda[\xi_{is}(t)]}&j\in allowed_k\\ 44 | 0&otherwise 45 | \end{cases}\tag{3} 46 | $$ 47 | 48 | >其中 $μ_{ij}(t)$ 是角度引导因子,计算如公式(4)所示; $λ$ 为角度引导因子的权重系数; $ξ_{ib}(t)$ 为自适应障碍物剔除因子,取值范围为 $[0,1]$,计算如式(5)所示; 49 | 50 | $$ 51 | \mu_{ij}(t)=\frac{1}{cos\phi}=\frac{|y_j-y_G|}{d_{jG}}\tag{4} 52 | $$ 53 | 54 | ![ref](images/IAACO-1.jpg) 55 | 56 | >角度引导因子 $μ_{ij}$ 主要考虑线段 $l_{jG}$ 和 $l_{SG}$ 之间的夹角对路径搜索的影响。 如上图所示,角度 $φ$ 越大,$l_{jG}$ 越接近理想路径 $l_{SG}$,从而增强了引导效果,加快了算法的收敛速度。其中 $ϕ$ 为线段 $l_{jG}$ 与 $l_{SG}$ 夹角的共角;$(x_j,y_j)$ 为待选第 $j$ 个网格的纵坐标,$(x_G,y_G)$ 为目标纵坐标 网格 $G$。 57 | 58 | $$ 59 | \xi_{ib}(t)=\begin{cases} 60 | 0&d_{ib}2R_s 63 | \end{cases}\tag{5} 64 | $$ 65 | 66 | >$d_{ib}$ 是第 $i$ 个网格到最近的第 $b$ 个障碍网格的最小距离; $R_s$ 为机器人避障的最小安全半径阈值,其值与机器人本身的尺寸有关; 67 | 68 | 同时,为了提高ACO的搜索质量,避免陷入局部最优解,本文采用参数自适应伪随机传递策略,如式 (6) 所示。 69 | 70 | $$ 71 | j=\begin{cases} 72 | argmax\{[\tau_{ij}(t)]^\alpha [\eta_{ij}(t)]^\beta[\mu_{ij}(t)]^\lambda[\xi_{ib}(t)]\}&q\leq q_0\\ 73 | P_{ij}^k(t)&otherwise 74 | \end{cases}\tag{6} 75 | $$ 76 | 77 | >其中 $q_0$ 是自适应转移概率的阈值,求解方式如公式 (7) 所示; $q$ 是在 $[0,1]$ 中均匀分布的随机变量。 78 | 79 | $$ 80 | q_0=δ_0e^{-\frac{1}{2}(\frac{N_c}{N_{max}})^2}\tag{7} 81 | $$ 82 | 83 | > 其中 $δ_0$ 为比例系数,取值范围为 $[0.1,0.5]$;从公式 (7) 可以看出前期 $q_0$ 值较大,有利于加入蚂蚁根据全局路径信息选择有利路径,提高收敛速度; 后期 $q_0$ 的值较小,有利于蚂蚁通过转移概率的随机搜索提高全局搜索能力。 84 | 85 | ### 3.3 改进信息素更新规则 86 | 87 | 针对 $ACO$ 的全局信息素更新不能引导蚂蚁及时寻找最优解的问题,提出了一种高质量的蚂蚁更新规则,即每次迭代后,只有蚂蚁路径的信息素到达目标点根据方程更新。使用原始更新公式并且被困在死锁中的蚂蚁会被丢弃,该操作可以避免全局信息素的盲目更新。然后根据全局引导规则更新路径的信息素。每次迭代后,根据方程 (8) 增强最优遍历路径的信息素,同时根据方程 (9) 削弱最坏蚂蚁遍历路径的信息素。通过高质量的全局信息素更新策略,蚂蚁的搜索范围更加集中在最优路径方向的邻域,最终实现全局优化,可以有效提高算法的收敛速度和搜索质量。改进的全局信息素浓度显示在方程中: 88 | 89 | $$ 90 | \tau_{ij}(t+1)=(1-\rho)\tau_{ij}(t)+\rho(\frac{Q}{J_{best}}\times\frac{J_{best}+J_{worst}}{2})\qquad ij\in p_{bs} \tag{8} 91 | $$ 92 | $$ 93 | \tau_{ij}(t+1)=(1-\rho)\tau_{ij}(t)+\rho(-\frac{Q}{J_{worst}})\qquad ij\in p_{ws} \tag{9} 94 | $$ 95 | >其中 $J_{best}$ 是本次迭代最优路径的多目标值; $J_{worst}$ 是本次迭代的最坏路径的多目标值; $p_{bs}$ 是本次迭代的最优路径; $p_{ws}$ 是本次迭代的最差路径。 96 | 97 | 在 $ACO$ 寻找最优解的过程中,除了信息素浓度的更新规律外,信息素挥发因子也会影响算法的性能。 本文采用自适应信息素挥发因子 $ρ$ 来调整算法的全局性和收敛速度,如式 (10) 所示: 98 | $$ 99 | \rho=k(\frac{L_{SG}}{J_{best}})\tag{10} 100 | $$ 101 | 102 | >其中 $κ$ 为调整系数,取值为小于 1 的正数; $L_{SG}$ 是路径的起始网格 $S$ 到目标网格 $G$ 的线性欧几里德距离。 算法前期,由于 $J_{best}$ 较大,挥发因子 $ρ$ 较小,因此各路径的信息素浓度差异较小,蚁群的引导功能减弱,增强了蚂蚁的全局搜索范围, 算法的准确性。 由于 $J_{best}$ 越来越小,使得波动因子 $ρ$ 迅速增大,各路信息素浓度差增大,增强了蚁群的引导功能,可以提高蚁群的搜索速度,使算法收敛迅速。 103 | 104 | ### 3.4 参数设置 105 | 106 | - $\sigma_1=0.1$ 107 | - $\sigma_2=0.9$ 108 | - $R_s=0.5$ 109 | - $\delta_0=0.15$ 110 | - $Q=2.5$ 111 | - $k_L=0.7$ 112 | - $k_S=0.1$ 113 | - $k_E=0.2$ 114 | - $m=50$ 115 | - $N_{max}=100$ 116 | 117 | ## 代码编写 118 | 119 | 由于该算法是专用于机器人路径规划当中,因此有些参数是在该问题中特有的,比如 $d_{ib}、R_s$ 等。本人并未进行路径规划类研究,暂时无精力去专门编写该文代码,因此如果是有同志需要代码,可以自己按照以上讲解进行代码编写。 120 | 121 | 若有出入,以参考文献为主。 122 | 123 | ## 参考文献 124 | 125 | [1] Miao C , Chen G , Yan C , et al. Path planning optimization of indoor mobile robot based on adaptive ant colony algorithm[J]. Computers & Industrial Engineering, 2021:107230. 126 | -------------------------------------------------------------------------------- /蚁群优化算法/最大最小蚂蚁系统/code/matlab/Asymmetry_MMAS.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 最大最小蚂蚁系统:非对称版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | %% 输出: 9 | % minimal_path:最短路径序列 10 | % minimal_length:最短路径长度 11 | %% --------------------------------------------------------------------%% 12 | function [minimal_path,minimal_length] = Asymmetry_MMAS(x,y,iterate_max) 13 | % 获取城市数目 14 | city_num = length(x); 15 | % 设置蚂蚁数目 16 | % ants = 20; 17 | ants = city_num; 18 | % 路径的相对重要性参数 19 | alpha = 1; 20 | % 能见度的相对重要性参数 21 | beta = 2; 22 | % 信息素持久性 23 | rho = 0.98; 24 | % 初始化各路径之间的信息素,对各路径赋予一个足够小的常数 25 | tau = ones(city_num) * 1e-5; 26 | pBest = 0.05; 27 | % 各城市之间的距离 28 | distance = zeros(city_num); 29 | for i = 1:city_num 30 | for j = i+1:city_num 31 | distance(i,j) = sqrt((x(i)-x(j))^2+(y(i)-y(j))^2); 32 | distance(j,i) = distance(i,j); 33 | end 34 | end 35 | distance_diag = ones(1,city_num) .* 1e-5; 36 | distance_diag = diag(distance_diag); 37 | distance = distance_diag + distance; 38 | % 路径的能见度,使用距离的倒数 39 | eta = 1 ./ distance; 40 | % 记录最短路径 41 | minimal_path = zeros(1,city_num); 42 | % 记录最短路径的长度 43 | minimal_length = inf; 44 | iterate = 0; 45 | while iterate < iterate_max 46 | % 生成一个禁忌表,禁忌表大小为ants行,city_num列 47 | tabu = zeros(ants,city_num); 48 | % 将所有蚂蚁分布在不同的城市起点 49 | random_city = randperm(city_num); 50 | for i = 1:ants 51 | city_index = randperm(length(random_city),1); 52 | city = random_city(city_index); 53 | random_city(city_index) = []; 54 | tabu(i,city) = 1; 55 | end 56 | % 蚂蚁通过相应的公式选择对应路径进行移动,并求解对应蚂蚁走过的路径长度 57 | ants_track_length = zeros(1,ants); 58 | for i = 2:city_num 59 | for j = 1:ants 60 | allowed = find(tabu(j,:) == 0); 61 | start_city = find(tabu(j,:) == i-1); 62 | visited_probability = ((tau(start_city,allowed).^alpha) .* (eta(start_city,allowed).^beta)) ./ (sum((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta))); 63 | visited_probability = cumsum(visited_probability); 64 | % 轮盘赌方式选择路径 65 | q = rand; 66 | visit_city_index = find(visited_probability > q,1); 67 | visit_city = allowed(visit_city_index); 68 | tabu(j,visit_city) = i; 69 | ants_track_length(j) = ants_track_length(j) + distance(tabu(j,:)==i-1,tabu(j,:)==i); 70 | end 71 | end 72 | for i = 1:ants 73 | ants_track_length(i) = ants_track_length(i) + distance(tabu(i,:)==city_num,tabu(i,:)==1); 74 | if min(ants_track_length) < minimal_length 75 | minimal_ant = i; 76 | minimal_length = min(ants_track_length); 77 | minimal_path = tabu(find(ants_track_length == min(ants_track_length),1),:); 78 | end 79 | end 80 | % 每次迭代时,信息素会挥发,信息素余量为 rho倍 81 | tau = rho .* tau; 82 | % 只增加最优路径上的信息素 83 | for j = 2:city_num 84 | tau(tabu(minimal_ant,:)==j-1,tabu(minimal_ant,:)==j) = tau(tabu(minimal_ant,:)==j-1,tabu(minimal_ant,:)==j) + 1/minimal_length; 85 | end 86 | tau(tabu(minimal_ant,:)==city_num,tabu(minimal_ant,:)==1) = tau(tabu(minimal_ant,:)==city_num,tabu(minimal_ant,:)==1) + 1/minimal_length; 87 | % 计算信息素上限 88 | tau_max = 1/((1-rho)*minimal_length); 89 | % 计算信息素下限 90 | avg = city_num / 2; 91 | tau_min = (tau_max * (1 - pBest^(1/city_num)))/((avg - 1) * pBest^(1/city_num)); 92 | % 限制信息素上下限 93 | tau(tautau_max) = tau_max; 95 | 96 | 97 | iterate = iterate + 1; 98 | end 99 | end 100 | 101 | 102 | -------------------------------------------------------------------------------- /蚁群优化算法/最大最小蚂蚁系统/code/matlab/DrawPath.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 路径绘画函数 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | % minimal_path:最短路径序列 9 | %% --------------------------------------------------------------------%% 10 | function [] = DrawPath(x,y,minimal_path) 11 | % 画图,首先需要最短路径的对应城市访问顺序 12 | city_num = length(x); 13 | sequence_x = zeros(1,city_num+1); 14 | sequence_y = zeros(1,city_num+1); 15 | for i = 1:city_num 16 | city_index = find(minimal_path == i); 17 | sequence_x(i) = x(city_index); 18 | sequence_y(i) = y(city_index); 19 | end 20 | city_index = find(minimal_path == 1); 21 | sequence_x(city_num+1) = x(city_index); 22 | sequence_y(city_num+1) = y(city_index); 23 | % scatter(x,y,'k',"filled"); 24 | plot(sequence_x,sequence_y,'g-o','MarkerFaceColor','k'); 25 | end 26 | 27 | -------------------------------------------------------------------------------- /蚁群优化算法/最大最小蚂蚁系统/code/matlab/Symmetry_MMAS.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 最大最小蚂蚁系统:对称版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | %% 输出: 9 | % minimal_path:最短路径序列 10 | % minimal_length:最短路径长度 11 | %% --------------------------------------------------------------------%% 12 | function [minimal_path,minimal_length] = Symmetry_MMAS(x,y,iterate_max) 13 | % 获取城市数目 14 | city_num = length(x); 15 | % 设置蚂蚁数目 16 | % ants = 20; 17 | ants = city_num; 18 | % 路径的相对重要性参数 19 | alpha = 1; 20 | % 能见度的相对重要性参数 21 | beta = 2; 22 | % 信息素持久性 23 | rho = 0.98; 24 | % 初始化各路径之间的信息素,对各路径赋予一个足够小的常数 25 | tau = ones(city_num) * 1e-5; 26 | pBest = 0.05; 27 | % 各城市之间的距离 28 | distance = zeros(city_num); 29 | for i = 1:city_num 30 | for j = i+1:city_num 31 | distance(i,j) = sqrt((x(i)-x(j))^2+(y(i)-y(j))^2); 32 | distance(j,i) = distance(i,j); 33 | end 34 | end 35 | distance_diag = ones(1,city_num) .* 1e-5; 36 | distance_diag = diag(distance_diag); 37 | distance = distance_diag + distance; 38 | % 路径的能见度,使用距离的倒数 39 | eta = 1 ./ distance; 40 | % 记录最短路径 41 | minimal_path = zeros(1,city_num); 42 | % 记录最短路径的长度 43 | minimal_length = inf; 44 | iterate = 0; 45 | while iterate < iterate_max 46 | % 生成一个禁忌表,禁忌表大小为ants行,city_num列 47 | tabu = zeros(ants,city_num); 48 | % 将所有蚂蚁分布在不同的城市起点 49 | random_city = randperm(city_num); 50 | for i = 1:ants 51 | city_index = randperm(length(random_city),1); 52 | city = random_city(city_index); 53 | random_city(city_index) = []; 54 | tabu(i,city) = 1; 55 | end 56 | % 蚂蚁通过相应的公式选择对应路径进行移动,并求解对应蚂蚁走过的路径长度 57 | ants_track_length = zeros(1,ants); 58 | for i = 2:city_num 59 | for j = 1:ants 60 | allowed = find(tabu(j,:) == 0); 61 | start_city = find(tabu(j,:) == i-1); 62 | visited_probability = ((tau(start_city,allowed).^alpha) .* (eta(start_city,allowed).^beta)) ./ (sum((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta))); 63 | visited_probability = cumsum(visited_probability); 64 | % 轮盘赌方式选择路径 65 | q = rand; 66 | visit_city_index = find(visited_probability > q,1); 67 | visit_city = allowed(visit_city_index); 68 | tabu(j,visit_city) = i; 69 | ants_track_length(j) = ants_track_length(j) + distance(tabu(j,:)==i-1,tabu(j,:)==i); 70 | end 71 | end 72 | for i = 1:ants 73 | ants_track_length(i) = ants_track_length(i) + distance(tabu(i,:)==city_num,tabu(i,:)==1); 74 | if min(ants_track_length) < minimal_length 75 | minimal_ant = i; 76 | minimal_length = min(ants_track_length); 77 | minimal_path = tabu(find(ants_track_length == min(ants_track_length),1),:); 78 | end 79 | end 80 | % 每次迭代时,信息素会挥发,信息素余量为 rho倍 81 | tau = rho .* tau; 82 | % 只增加最优路径上的信息素 83 | for j = 2:city_num 84 | tau(tabu(minimal_ant,:)==j-1,tabu(minimal_ant,:)==j) = tau(tabu(minimal_ant,:)==j-1,tabu(minimal_ant,:)==j) + 1/minimal_length; 85 | tau(tabu(minimal_ant,:)==j,tabu(minimal_ant,:)==j-1) = tau(tabu(minimal_ant,:)==j-1,tabu(minimal_ant,:)==j); 86 | end 87 | tau(tabu(minimal_ant,:)==city_num,tabu(minimal_ant,:)==1) = tau(tabu(minimal_ant,:)==city_num,tabu(minimal_ant,:)==1) + 1/minimal_length; 88 | tau(tabu(minimal_ant,:)==1,tabu(minimal_ant,:)==city_num) = tau(tabu(minimal_ant,:)==city_num,tabu(minimal_ant,:)==1); 89 | % 计算信息素上限 90 | tau_max = 1/((1-rho)*minimal_length); 91 | % 计算信息素下限 92 | avg = city_num / 2; 93 | tau_min = (tau_max * (1 - pBest^(1/city_num)))/((avg - 1) * pBest^(1/city_num)); 94 | % 限制信息素上下限 95 | tau(tautau_max) = tau_max; 97 | 98 | 99 | iterate = iterate + 1; 100 | end 101 | end 102 | 103 | 104 | -------------------------------------------------------------------------------- /蚁群优化算法/最大最小蚂蚁系统/最大最小蚂蚁系统.md: -------------------------------------------------------------------------------- 1 | # 最大最小蚂蚁系统(MAX-Min Ant System,MMAS) 2 | 3 | ## 1 引言 4 | 5 | 最大最小蚂蚁系统是基于蚂蚁系统(**AS**)进行改进的产物,由于本文不再赘述关于蚂蚁系统内容,因此读者需先去阅读已完成的[蚂蚁系统](../蚂蚁系统/蚂蚁系统.md)文章。 6 | 7 | 本文中讨论的 **MAX-MIN Ant System (MMAS)** 算法通过仅允许最佳解决方案在信息素轨迹更新期间添加信息素,实现了对搜索历史的强大利用。 此外,使用相当简单的机制来限制信息素轨迹的强度有效地避免了搜索的过早收敛。 最后,MMAS 可以通过添加本地搜索算法轻松扩展。 8 | 9 | 文中主要测试领域: 10 | 11 | - 旅行商问题 12 | - 二次分配问题 13 | 14 | 需要指出以下问题: 15 | 16 | >1. 因本文是基于AS改进,因此在描述基本算法时以AS为准 17 | >2. 在本文中关于AS的某些描述存在不一致,本人以AS原文描述为准 18 | >3. 若与本文参考文献存在冲突,请以参考文献为主 19 | 20 | 下面直接进入主题。 21 | 22 | ## 2 最大最小蚂蚁系统(MMAS) 23 | 24 | 对 **ACO**(包括蚂蚁系统、蚁群系统、精华蚂蚁系统、基于排列的蚂蚁系统) 的研究表明,可以通过对搜索过程中找到的最佳解决方案的更强利用来提高性能。 然而,使用更贪婪的搜索可能会加剧搜索过早停滞的问题。 因此,实现 ACO 算法最佳性能的关键是将搜索过程中发现的最佳解决方案的改进利用与避免早期搜索停滞的有效机制相结合。最大最小蚂蚁系统($MMAS$)专为满足这些要求而开发,在三个关键方面与 AS 不同: 25 | 26 | - 1. 为了利用在迭代期间或算法运行期间找到的最佳解决方案,在每次迭代之后只有一只蚂蚁添加信息素。 该蚂蚁可能是在当前迭代中找到最佳解决方案的蚂蚁(迭代-最佳蚂蚁),也可能是从试验开始就找到最佳解决方案的蚂蚁(全局最佳蚂蚁)。 27 | - 2. 为了避免搜索停滞,每个解决方案组件上可能的信息素踪迹的范围被限制在一个区间 $[τ_{min},τ_{max}]$。 28 | - 3. 此外,将信息素轨迹初始化为 $τ_{max}$,以这种方式在算法开始时实现对解决方案的更高探索。 29 | 30 | ### 2.1 信息素轨迹更新 31 | 32 | 在 MMAS 中,每次迭代后仅使用一只蚂蚁来更新信息素轨迹。 因此,修改后的信息素踪迹更新规则如公式(1)所示: 33 | 34 | $$ 35 | \tau_{ij}(t+1)=\rho \tau_{ij}(t)+\Delta\tau_{ij}^{best}\tag{1} 36 | $$ 37 | 38 | >该更新方式和蚁群系统($ACS$)基本一致,不过在$\Delta\tau_{ij}^{best}$少了一个常数系数,另外,在$ACS$中,虽然只对最优路径增加信息素,但对于其他路径,信息素蒸发是一样执行的。其中 $\Delta\tau_{ij}^{best} = \frac{1}{f(s^{best})}$ ,其中 $s^{best}$ 可以选择当前迭代最优路径长度 $s_{ib}$或迭代至目前位置最优路径长度 $s_{gb}$。即在$MMAS$中,只更新当前最优的路径信息素。 39 | 40 | 仅使用 $s_{ib}$或 $s_{gb}$一种解决方案进行信息素更新是 $MMAS$中搜索利用的最重要手段。通过这种选择,经常出现在最佳解决方案中的解决方案元素得到了很大的加强。尽管如此,在用于更新信息素轨迹的迭代最佳和全局最佳蚂蚁之间的不同更新方式控制着搜索历史的利用方式。 41 | 42 | - 当仅使用 $s_{gb}$时,搜索可能会过快地集中在此解决方案上,并且对可能更好的解决方案的探索受到限制,从而有陷入劣质解决方案的危险。 43 | - 当为信息素轨迹更新选择 $s_{ib}$时,这种危险会降低,因为迭代最佳解决方案可能因迭代而异,并且大量的解决方案组件可能会偶尔得到强化。 44 | - 使用混合策略,例如选择 $s_{ib}$作为更新信息素的默认值,并且仅在每固定次数的迭代中使用 $s_{gb}$。 45 | 46 | > 在作者的测试结果中,最好的策略似乎是使用动态混合策略,这增加了信息素使用$s_{gb}$的频率在搜索期间更新。 47 | 48 | ### 2.2 信息素限制 49 | 50 | 在单独使用信息素轨迹更新方式时,算法在迭代一定次数后便会陷入停滞状态。 51 | 52 | 显然,应该避免这种停滞的情况。实现这一点的一种方法是扰动选择下一个解决方案组件的概率,这直接取决于信息素轨迹和启发式信息。 53 | 54 | 在整个算法运行过程中,启发式信息通常与问题相关并且是静态的。但是通过限制信息素轨迹的影响,可以很容易地避免在算法运行期间信息素轨迹之间的相对差异变得过于极端。为了实现这一目标,$MMAS$对最小和最大信息素轨迹施加了明确的限制 $τ_{min}$ 和 $τ_{max}$,这样对于所有信息素轨迹 $τ_{ij} (t)$,$τ_{min} ≤ τ_{ij} (t) ≤ τ_{max}$。每次迭代后,必须确保信息素踪迹遵守限制。如果我们有 $τ_{ij} (t)>τ_{max}$,则设置 $τ_{ij} (t) = τ_{max}$;类似地,如果 $τ_{ij} (t)<τ_{min}$,则设置$τ_{ij} (t) = τ_{min}$。 55 | 56 | >在设置 $\tau_{min}、\tau_{max}$过程中,需要注意$\tau_{min}$应该大于0,同时 $\tau_{max}$不能过大。 57 | 58 | 在文章中,对 $τ_{max}$ 的由来做了比较多的描述,但是简单来说,$τ_{max}$是根据公式 (2) 动态取值的。 59 | 60 | $$ 61 | \tau_{max}=\frac{1}{(1-\rho)}\frac{1}{f(s^{opt})}\tag{2} 62 | $$ 63 | 64 | >其中 $f(s^{opt})$为每次迭代的最短路径,即该值是动态改变的,$\rho$为信息素蒸发系数。在这里需要提醒,$τ_{max}$一开始并不需要,在一次迭代产生最短路径之后才会随之初始化。 65 | 66 | 为了确定$τ_{min}$的合理值,作者使用以下假设: 67 | 68 | - 在搜索停滞发生前不久找到最佳解决方案。 在这种情况下,在一次算法迭代中重建全局最佳解决方案的概率明显高于零。 可能会在找到的最佳解决方案附近找到更好的解决方案。 69 | - 对解决方案构建的主要影响是由信息素轨迹上下限的相对差异决定的,而不是由启发式信息的相对差异决定的。 70 | 71 | 上面假设对于了解算法实现用处并不是很大,下面直接给出$\tau_{min}$计算公式: 72 | 73 | $$ 74 | \tau_{min}=\frac{\tau_{max}(1-\sqrt[n]{P_{best}})}{(avg-1)\sqrt[n]{P_{best}}}\tag{3} 75 | $$ 76 | 77 | 其中$avg$计算公式如下: 78 | 79 | $$ 80 | avg=\frac{n}{2}\tag{4} 81 | $$ 82 | 83 | >其中对于$n$描述并不明确,在参数设置时提到$m=n$,且$m$为蚂蚁数量,那么,这里的$n$应该与蚂蚁数量相同。 84 | > 85 | >个人猜想,$n$应该代表城市数目,作者指的是蚂蚁数目必须等于城市数目 86 | 87 | ### 2.3 信息素轨迹初始化 88 | 89 | 从上面的分析可得出,无论是信息素下限$\tau_{min}$还是信息素上限$\tau_{max}$都是经过算法一次迭代运行之后才可得到。 90 | 91 | 因此,在信息素初始化阶段,可以对信息素进行统一初始化一个足够小的值。这对算法后续运行的影响并不大! 92 | 93 | ### 2.4 参数设置 94 | 95 | - β = 2 96 | - α = 1 97 | - m = n,其中 m 是蚂蚁的数量 98 | - ρ = 0.98 99 | - pbest = 0.05 100 | 101 | 在$MMAS$中,运行机制稍微与$ACS$不一致。作者提出,$MMAS$还需要自身去维护一个候选列表,该列表包含各城市最近邻居的非递减排序,即需要维护一个大小为$蚂蚁数目\times城市数目\times 20$的三维空间矩阵。当对应城市候选列表全部被选完之时,才从对应城市候选列表之外的城市进行选择。 102 | 103 | >对于候选列表,个人感觉有以下问题,首先它固定为20,当总城市数目不足二十,那么肯定就需要进行修改的;其次蚁群算法本身就是通过蚁群合作的正反馈进行合作并最终找到最短路径,通过人为的给出对应城市邻近20座城市的候选列表来使算法更加容易找到最短路径,该思想是否回到了贪婪式方法,且对于算法性能是否有足够的提升呢? 104 | 105 | ## 3 代码实现 106 | 107 | 该文代码实现情况如下: 108 | 109 | - 在实现代码时并未采取候选列表的形式 110 | - 代码中,按照$m=n$,即城市数目等于蚂蚁数目 111 | 112 | ## 4 参考文献 113 | 114 | [1]Stützle T, Hoos H H. MAX–MIN ant system[J]. Future generation computer systems, 2000, 16(8): 889-914. 115 | -------------------------------------------------------------------------------- /蚁群优化算法/蚁群系统/code/matlab/Asymmetry_ACS.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 蚂蚁系统:非对称版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | %% 输出: 9 | % minimal_path:最短路径序列 10 | % minimal_length:最短路径长度 11 | %% --------------------------------------------------------------------%% 12 | function [minimal_path,minimal_length] = Asymmetry_ACS(x,y,iterate_max) 13 | % 获取城市数目 14 | city_num = length(x); 15 | % 设置蚂蚁数目 16 | ants = 20; 17 | % 全局信息素更新参数 18 | alpha = 0.1; 19 | % 能见度的相对重要性参数 20 | beta = 2; 21 | % 局部信息素更新参数 22 | rho = 0.1; 23 | % 选择阈值(通过q0在开发及有偏探索中进行选择) 24 | q0 = 0.9; 25 | % 初始化各路径之间的信息素,对各路径赋予一个足够小的常数 26 | tau = ones(city_num) * 1e-5; 27 | % 各城市之间的距离 28 | distance = zeros(city_num); 29 | for i = 1:city_num 30 | for j = i+1:city_num 31 | distance(i,j) = sqrt((x(i)-x(j))^2+(y(i)-y(j))^2); 32 | distance(j,i) = distance(i,j); 33 | end 34 | end 35 | distance_diag = ones(1,city_num) .* 1e-5; 36 | distance_diag = diag(distance_diag); 37 | distance = distance_diag + distance; 38 | % 路径的能见度,使用距离的倒数 39 | eta = 1 ./ distance; 40 | % 记录最短路径 41 | minimal_path = zeros(1,city_num); 42 | % 记录最短路径的长度 43 | minimal_length = inf; 44 | % 求解最近邻启发式产生的旅行长度 45 | L_nn = 0; 46 | L_nn_Tabu = zeros(1,city_num); 47 | L_nn_Tabu(1) = 1; 48 | for i = 2:city_num 49 | allowed = find(L_nn_Tabu == 0); 50 | start_city = find(L_nn_Tabu == i-1); 51 | visit_city_index = find(eta(start_city,allowed) == max(eta(start_city,allowed)),1); 52 | visit_city = allowed(visit_city_index); 53 | L_nn_Tabu(visit_city) = i; 54 | L_nn = L_nn + distance(L_nn_Tabu==i-1,L_nn_Tabu==i); 55 | end 56 | L_nn = L_nn + distance(L_nn_Tabu==city_num,L_nn_Tabu==1); 57 | 58 | iterate = 0; 59 | while iterate < iterate_max 60 | % 生成一个禁忌表,禁忌表大小为ants行,city_num列 61 | tabu = zeros(ants,city_num); 62 | % 将所有蚂蚁分布在不同的城市起点 63 | random_city = randperm(city_num); 64 | for i = 1:ants 65 | city_index = randperm(length(random_city),1); 66 | city = random_city(city_index); 67 | random_city(city_index) = []; 68 | tabu(i,city) = 1; 69 | end 70 | % 蚂蚁通过相应的公式选择对应路径进行移动,并求解对应蚂蚁走过的路径长度 71 | ants_track_length = zeros(1,ants); 72 | for i = 2:city_num 73 | for j = 1:ants 74 | allowed = find(tabu(j,:) == 0); 75 | start_city = find(tabu(j,:) == i-1); 76 | % 搜索路径状态选择 77 | q = rand; 78 | if q <= q0 79 | % 使用贪婪开发,即选择信息素最强的路径 80 | visited_probability = ((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta)); 81 | visit_city_index = find(visited_probability == max(visited_probability),1); 82 | else 83 | % 使用有偏探索,在一定概率上会选择较差的路径 84 | visited_probability = ((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta)) ./ (sum((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta))); 85 | visited_probability = cumsum(visited_probability); 86 | q = rand; 87 | visit_city_index = find(visited_probability > q,1); 88 | end 89 | visit_city = allowed(visit_city_index); 90 | tabu(j,visit_city) = i; 91 | tau(start_city,visit_city) = (1 - rho) .* tau(start_city,visit_city) + rho / (city_num * L_nn); 92 | ants_track_length(j) = ants_track_length(j) + distance(tabu(j,:)==i-1,tabu(j,:)==i); 93 | end 94 | end 95 | for i = 1:ants 96 | ants_track_length(i) = ants_track_length(i) + distance(tabu(i,:)==city_num,tabu(i,:)==1); 97 | tau(tabu(i,:)==city_num,tabu(i,:)==1) = (1 - rho) .* tau(tabu(i,:)==city_num,tabu(i,:)==1) + rho / (city_num * L_nn); 98 | if min(ants_track_length) < minimal_length 99 | minimal_length = min(ants_track_length); 100 | minimal_path = tabu(ants_track_length == minimal_length,:); 101 | end 102 | end 103 | 104 | % 信息素全局更新规则 105 | tau = (1-alpha).*tau; 106 | minimal_ants = size(minimal_path,1); 107 | for i = 1:minimal_ants 108 | for j = 2:city_num 109 | tau(minimal_path(i,:)==j-1,minimal_path(i,:)==j) = tau(minimal_path(i,:)==j-1,minimal_path(i,:)==j) + alpha / minimal_length; 110 | end 111 | tau(minimal_path(i,:)==city_num,minimal_path(i,:)==1) = tau(minimal_path(i,:)==city_num,minimal_path(i,:)==1) + alpha / minimal_length; tau(minimal_path(i,:)==1,minimal_path(i,:)==city_num) = tau(minimal_path(i,:)==city_num,minimal_path(i,:)==1); 112 | end 113 | iterate = iterate + 1; 114 | end 115 | end 116 | 117 | -------------------------------------------------------------------------------- /蚁群优化算法/蚁群系统/code/matlab/DrawPath.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 路径绘画函数 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | % minimal_path:最短路径序列 9 | %% --------------------------------------------------------------------%% 10 | function [] = DrawPath(x,y,minimal_path) 11 | % 画图,首先需要最短路径的对应城市访问顺序 12 | city_num = length(x); 13 | sequence_x = zeros(1,city_num+1); 14 | sequence_y = zeros(1,city_num+1); 15 | for i = 1:city_num 16 | city_index = find(minimal_path == i); 17 | sequence_x(i) = x(city_index); 18 | sequence_y(i) = y(city_index); 19 | end 20 | city_index = find(minimal_path == 1); 21 | sequence_x(city_num+1) = x(city_index); 22 | sequence_y(city_num+1) = y(city_index); 23 | % scatter(x,y,'k',"filled"); 24 | plot(sequence_x,sequence_y,'g-o','MarkerFaceColor','k'); 25 | end 26 | 27 | -------------------------------------------------------------------------------- /蚁群优化算法/蚁群系统/code/matlab/Symmetry_ACS.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 蚂蚁系统:对称版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | %% 输出: 9 | % minimal_path:最短路径序列 10 | % minimal_length:最短路径长度 11 | %% --------------------------------------------------------------------%% 12 | function [minimal_path,minimal_length] = Symmetry_ACS(x,y,iterate_max) 13 | % 获取城市数目 14 | city_num = length(x); 15 | % 设置蚂蚁数目 16 | ants = 20; 17 | % 全局信息素更新参数 18 | alpha = 0.1; 19 | % 能见度的相对重要性参数 20 | beta = 2; 21 | % 局部信息素更新参数 22 | rho = 0.1; 23 | % 选择阈值(通过q0在开发及有偏探索中进行选择) 24 | q0 = 0.9; 25 | % 初始化各路径之间的信息素,对各路径赋予一个足够小的常数 26 | tau = ones(city_num) * 1e-5; 27 | % 各城市之间的距离 28 | distance = zeros(city_num); 29 | for i = 1:city_num 30 | for j = i+1:city_num 31 | distance(i,j) = sqrt((x(i)-x(j))^2+(y(i)-y(j))^2); 32 | distance(j,i) = distance(i,j); 33 | end 34 | end 35 | distance_diag = ones(1,city_num) .* 1e-5; 36 | distance_diag = diag(distance_diag); 37 | distance = distance_diag + distance; 38 | % 路径的能见度,使用距离的倒数 39 | eta = 1 ./ distance; 40 | % 记录最短路径 41 | minimal_path = zeros(1,city_num); 42 | % 记录最短路径的长度 43 | minimal_length = inf; 44 | % 求解最近邻启发式产生的旅行长度 45 | L_nn = 0; 46 | L_nn_Tabu = zeros(1,city_num); 47 | L_nn_Tabu(1) = 1; 48 | for i = 2:city_num 49 | allowed = find(L_nn_Tabu == 0); 50 | start_city = find(L_nn_Tabu == i-1); 51 | visit_city_index = find(eta(start_city,allowed) == max(eta(start_city,allowed)),1); 52 | visit_city = allowed(visit_city_index); 53 | L_nn_Tabu(visit_city) = i; 54 | L_nn = L_nn + distance(L_nn_Tabu==i-1,L_nn_Tabu==i); 55 | end 56 | L_nn = L_nn + distance(L_nn_Tabu==city_num,L_nn_Tabu==1); 57 | 58 | iterate = 0; 59 | while iterate < iterate_max 60 | % 生成一个禁忌表,禁忌表大小为ants行,city_num列 61 | tabu = zeros(ants,city_num); 62 | % 将所有蚂蚁分布在不同的城市起点 63 | random_city = randperm(city_num); 64 | for i = 1:ants 65 | city_index = randperm(length(random_city),1); 66 | city = random_city(city_index); 67 | random_city(city_index) = []; 68 | tabu(i,city) = 1; 69 | end 70 | % 蚂蚁通过相应的公式选择对应路径进行移动,并求解对应蚂蚁走过的路径长度 71 | ants_track_length = zeros(1,ants); 72 | for i = 2:city_num 73 | for j = 1:ants 74 | allowed = find(tabu(j,:) == 0); 75 | start_city = find(tabu(j,:) == i-1); 76 | % 搜索路径状态选择 77 | q = rand; 78 | if q <= q0 79 | % 使用贪婪开发,即选择信息素最强的路径 80 | visited_probability = ((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta)); 81 | visit_city_index = find(visited_probability == max(visited_probability),1); 82 | visit_city = allowed(visit_city_index); 83 | else 84 | % 使用有偏探索,在一定概率上会选择较差的路径 85 | visited_probability = ((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta)) ./ (sum((tau(start_city,allowed)) .* (eta(start_city,allowed).^beta))); 86 | visited_probability = cumsum(visited_probability); 87 | q = rand; 88 | visit_city_index = find(visited_probability > q,1); 89 | visit_city = allowed(visit_city_index); 90 | end 91 | tabu(j,visit_city) = i; 92 | tau(start_city,visit_city) = (1 - rho) .* tau(start_city,visit_city) + rho / (city_num * L_nn); 93 | tau(visit_city,start_city) = tau(start_city,visit_city); 94 | ants_track_length(j) = ants_track_length(j) + distance(tabu(j,:)==i-1,tabu(j,:)==i); 95 | end 96 | end 97 | for i = 1:ants 98 | ants_track_length(i) = ants_track_length(i) + distance(tabu(i,:)==city_num,tabu(i,:)==1); 99 | tau(tabu(i,:)==city_num,tabu(i,:)==1) = (1 - rho) .* tau(tabu(i,:)==city_num,tabu(i,:)==1) + rho / (city_num * L_nn); 100 | tau(tabu(i,:)==1,tabu(i,:)==city_num) = tau(tabu(i,:)==city_num,tabu(i,:)==1); 101 | if min(ants_track_length) < minimal_length 102 | minimal_length = min(ants_track_length); 103 | minimal_path = tabu(ants_track_length == minimal_length,:); 104 | end 105 | end 106 | 107 | 108 | % 信息素全局更新规则 109 | tau = (1-alpha).*tau; 110 | minimal_ants = size(minimal_path,1); 111 | for i = 1:minimal_ants 112 | for j = 2:city_num 113 | tau(minimal_path(i,:)==j-1,minimal_path(i,:)==j) = tau(minimal_path(i,:)==j-1,minimal_path(i,:)==j) + alpha / minimal_length; 114 | tau(minimal_path(i,:)==j,minimal_path(i,:)==j-1) = tau(minimal_path(i,:)==j-1,minimal_path(i,:)==j); 115 | end 116 | tau(minimal_path(i,:)==city_num,minimal_path(i,:)==1) = tau(minimal_path(i,:)==city_num,minimal_path(i,:)==1) + alpha / minimal_length; 117 | tau(minimal_path(i,:)==1,minimal_path(i,:)==city_num) = tau(minimal_path(i,:)==city_num,minimal_path(i,:)==1); 118 | end 119 | iterate = iterate + 1; 120 | end 121 | end 122 | 123 | -------------------------------------------------------------------------------- /蚁群优化算法/蚁群系统/images/ACS-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/蚁群优化算法/蚁群系统/images/ACS-1.jpg -------------------------------------------------------------------------------- /蚁群优化算法/蚁群系统/蚁群系统.md: -------------------------------------------------------------------------------- 1 | # 蚁群系统(Ant Colony System,ACS) 2 | 3 | ## 1 引言 4 | 5 | 蚂蚁算法所基于的自然隐喻是蚁群的隐喻。 真正的蚂蚁能够通过利用信息素信息,在不使用视觉线索的情况下找到从食物来源到它们的巢穴的最短路径。 行走时,蚂蚁会在地面上沉积信息素,并且可能会跟随其他蚂蚁先前沉积的信息素。 在图一中,我们展示了一种蚂蚁利用信息素找到两点之间最短路径的方法。 6 | 7 | 考虑图 1($a$):蚂蚁到达一个决定点,在这个点上它们必须决定是向左转还是向右转。由于他们不知道哪个是最佳选择,他们随机选择。可以预期,平均而言,一半的蚂蚁决定向左转,另一半决定向右转。从左向右移动的蚂蚁(名字以 $L$ 开头的蚂蚁)和从右向左移动的蚂蚁(名字以 $R$ 开头)都会发生这种情况。图 1($b$) 和 ($c$) 显示了接下来的瞬间发生的情况,假设所有蚂蚁以大致相同的速度行走。虚线的数量大致与蚂蚁沉积在地面上的信息素数量成正比。由于下部路径比上部路径短,因此平均有更多蚂蚁会访问它,因此信息素积累得更快。经过短暂的过渡期后,两条路径上的信息素数量差异足够大,以影响新蚂蚁进入系统的决定[如图 1($d$) 所示]。从现在开始,新蚂蚁在概率上会更倾向于选择较低的路径,因为在决策点,它们会在较低的路径上感知到更多的信息素。这反过来又增加了,具有正反馈效应,选择较低和较短路径的蚂蚁数量。很快所有蚂蚁都将使用较短的路径。 8 | 9 | ![ref](images/ACS-1.jpg) 10 | 11 | 真实蚂蚁的上述行为启发了蚂蚁系统,一种由一组人工蚂蚁通过沉积在图边上的信息素交换信息来协作解决问题的算法。蚂蚁系统已应用于如下组合优化问题: 12 | 13 | - 旅行商问题 ($TSP$) 14 | - 二次分配问题 15 | 16 | 本文中介绍的算法蚁群系统 ($ACS$) 建立在先前的蚂蚁系统 ($AS$) 的基础上,旨在提高应用于对称和非对称 $TSP$ 时的效率。主要思想是让一组称为蚂蚁的代理并行搜索 $TSP$ 的良好解决方案,并通过信息素介导的间接和全局通信进行合作。非正式地,每只蚂蚁以迭代的方式构建一个 $TSP$ 解决方案:它通过利用从过去的经验中获得的信息和贪婪的启发式方法,将新城市添加到部分解决方案中。记忆采用蚂蚁在 $TSP$ 边上沉积的信息素的形式,而启发式信息仅由边的长度给出。 17 | 18 | ## 2 蚁群系统(Ant Colony System,ACS) 19 | 20 | $ACS$ 与以前的蚂蚁系统不同,主要有以下三个方面: 21 | 22 | - i 状态转换规则提供了一种直接的方法来平衡新边的探索和先验知识的利用,以及关于问题的累积知识 23 | - ii 全局更新规则是仅适用于属于最佳蚂蚁旅行的边 24 | - iii 在蚂蚁构建解决方案时,应用了局部信息素更新规则(简称局部更新规则) 25 | 26 | 非正式地,$ACS$ 的工作方式如下:蚂蚁最初定位在根据一些初始化规则(例如,随机)选择的城市上。每只蚂蚁通过重复应用随机贪婪规则(状态转换规则)来构建一个游览路线(即 $TSP$ 的可行解)。在构建它的旅程时,蚂蚁还通过应用本地更新规则来修改访问边缘上的信息素数量。一旦所有蚂蚁都终止了它们的旅行,边缘上的信息素数量将再次修改(通过应用全局更新规则)。就像在蚂蚁系统中的情况一样,蚂蚁在构建它们的旅行时受到启发式信息(它们更喜欢选择短边)和信息素信息的指导。具有大量信息素的边缘是非常理想的选择。信息素更新规则的设计使得它们倾向于向蚂蚁应该访问的边缘提供更多的信息素。 27 | 28 | 下面通过以下三方面来介绍 $ACS$ 算法: 29 | 30 | - 状态转换规则 31 | - 全局更新规则 32 | - 局部更新规则 33 | 34 | ### 2.1 ACS 状态转换规则 35 | 36 | 在 $ACS$ 中,状态转换规则如下:位于节点上的蚂蚁通过公式(1)给出的规则选择要移动的城市: 37 | 38 | $$ 39 | s=\begin{cases} 40 | arg\;max_{u\in allowed_r^k}\{[τ(r,u)]\cdot[\eta(r,u)]^\beta\}&if \;q\leq q_0(开发)\\ 41 | S&otherwise(有偏探索) 42 | \end{cases}\tag{1} 43 | $$ 44 | 45 | >其中 $q$ 是均匀分布在的 $[0,1]$ 之间随机数,$q_0$ 是一个在 $[0,1]$ 之间取值的参数,$S$ 是根据公式(2)中给出的概率分布选择的随机变量,在选择时选择概率最大的城市。 46 | 47 | $$ 48 | p_k(r,s)=\begin{cases} 49 | \frac{[τ(r,s)]\cdot[\eta(r,s)]^\beta}{\sum_{i\in allowed_r^k}[τ(r,i)]\cdot[\eta(r,i)]^\beta}&if\; s\in allowed_r^k\\ 50 | 0&otherwise 51 | \end{cases}\tag{2} 52 | $$ 53 | 54 | > 1. 其中称 $η(i,j)$ 为能见度,其值取 $1/d(i,j)$,即两座城市之间路径长度的倒数,且该值在算法运行期间不会被修改。 55 | > 56 | > 2. 其中$allowed_i^k = {N - tabu_i^k}$,指除去第 $k$ 只蚂蚁已经走过的城市,即第 $k$ 只蚂蚁的禁忌表中含有的城市,更简单的记法,可以记作第 $k$ 只蚂蚁所在城市 $i$ 还能访问的城市集合。 $β$ 是控制轨迹与可见性的相对重要性的参数。 因此,转移概率是可见性(表示应该以高概率选择附近城镇,从而实施贪婪的建设性启发式)和时间 $t$ 的路径强度(表示直到时间 $t$ 如果在路径 $(i,j)$ 上有了更多的信息素累积,那么它是非常可取的,因此实现了自催化过程)。 57 | 58 | 由(1)和(2)产生的状态转换规则称为**伪随机比例规则**。 与之前的随机比例规则一样,此状态转换规则有利于向由短边连接并具有大量信息素的节点转换。 59 | 60 | 参数 $q_0$ 决定了开发与探索的相对重要性:每次城市 $r$ 中的蚂蚁必须选择城市 $s$ 移动时,它会采样一个随机数 $q(q\in[0,1])$。如果 $q\leq q_0$ 则是最佳边缘,根据公式 (1) 的规则,该蚂蚁将会被选择(开发),否则根据公式(2)(有偏探索)选择一条边。 61 | 62 | ### 2.2 ACS 全局更新规则 63 | 64 | 在 ACS 中,仅允许全局最好的蚂蚁(即从试验开始构建最短路径的蚂蚁)沉积信息素。 这种选择与伪随机比例规则的使用一起,旨在使搜索更加定向:蚂蚁在算法当前迭代中找到的最佳游览的邻域中进行搜索。 全局更新是在所有蚂蚁完成它们的旅行后进行的。 通过公式(3)的全局更新规则更新信息素: 65 | 66 | $$ 67 | τ(r,s)=(1-\alpha)\cdot τ(r,s)+\alpha\cdot \Delta τ(r,s)\tag{3} 68 | $$ 69 | 70 | >其中 $\Delta τ(r,s)$ 为对应路径 $(r,s)$ 上的信息素增量,计算公式如公式(4)所示。 71 | 72 | $$ 73 | \Delta τ(r,s)=\begin{cases} 74 | (L_{gb})^{-1}&if\;(r,s)\in global-best-tour\\ 75 | 0&otherwise 76 | \end{cases}\tag{4} 77 | $$ 78 | 79 | >其中 $\alpha(\alpha \in (0,1))$ 是信息素衰减参数,$L_{gb}$ 是从试验开始的全局最佳游览的长度。 与蚂蚁系统的情况一样,全局更新旨在为较短的旅行提供更多的信息素。 等式 (3) 规定只有那些属于全局最佳旅行的边才会得到强化。 我们还测试了另一种称为迭代最佳的全局更新规则,与上面称为全局最佳的规则相反,后者在(3)中使用 $L_{ib}$(试验当前迭代中的最佳游览的长度)。 此外,对于迭代最佳,接受强化的边是属于当前迭代的最佳路径的边。 实验表明,两种方案的差异很小,略偏向于 $global-best$,因此在以下实验中使用。 80 | > 81 | > - 从上面应该找到关键点,作者通过大量实验更加倾向于使用全局最优游览长度进行更新,而非当前最优游览长度。 82 | > - 需要特别注意,全局最优是从一开始到后续迭代最优秀的路径(有可能不止一条) 83 | 84 | ### 2.3 ACS 本地更新规则 85 | 86 | 在构建 TSP 的解决方案(即游览)时,蚂蚁通过公式(5)的局部更新规则访问边缘并改变其信息素: 87 | 88 | $$ 89 | τ(r,s)=(1-\rho)\cdot τ(r,s)+\rho\cdot \Delta τ(r,s)\tag{5} 90 | $$ 91 | 92 | >其中 $\rho$ 是一个参数,取值范围为 $\rho\in(0,1)$。 93 | 94 | 在文章中,作者对 $\Delta τ(r,s)$ 的取值做了三个实验,分别是得到三类实验结果及相应算法。使用公式 $\Delta τ(r,s)=r\cdot max_{z\in allowed_r^k}τ(s,z)$ 进行局部信息素更新的蚁群算法被称之为 $Ant-Q$(其中 $r$ 为一个参数,取值区间为 $[0,1)$);使用公式 $\Delta τ(r,s)=τ_0$ 进行局部信息素更新的被称为 $ACS$,即本文所描述的算法($τ_0$的取值将在下一小节给出);最后一种则是使 $\Delta τ(r,s)=0$,即不进行本地信息素更新。 95 | 96 | >经过作者的测试,结果为:$Ant-Q$ 与 $ACS$ 的效果差异并不显著,此外 $ACS$ 本地更新规则比 $Ant-Q$ 需要更少的计算。 97 | 98 | $ACS$ 本地更新规则的作用是对旅行过程中的可选路径进行洗牌,以便一个蚂蚁旅行中的早期城市可能会在其他蚂蚁旅行中被探索。 换句话说,局部更新的效果是使边缘的可取性动态变化:每次蚂蚁使用边缘时,它都会变得不太可取(因为它失去了一些信息素)。 通过这种方式,蚂蚁将更好地利用信息素信息:如果没有本地更新,所有蚂蚁都会在最好的先前旅行的狭窄邻域中进行搜索。 99 | 100 | ### 2.4 ACS 参数设置 101 | 102 | - $\beta=2$ 103 | - $q_0=0.9$ 104 | - $\alpha=\rho=0.1$ 105 | - $τ_0=(n\cdot L_{nn})^{-1}$ 106 | 107 | >其中 $L_{nn}$ 是最近邻启发式产生的旅行长度,通俗来讲,就是按照贪婪的方式,每次都选择对应城市距离最短的那个城市相连接的路径长度。 108 | > 109 | >当你思考的时候会发现,通过该方式得到的路径长度并不唯一,它一定程度取决于一开始放置的起点城市。 110 | 111 | ## 3 代码实现 112 | 113 | ## 4 参考文献 114 | 115 | [1]Dorigo M, Gambardella L M. Ant colony system: a cooperative learning approach to the traveling salesman problem[J]. IEEE Transactions on evolutionary computation, 1997, 1(1): 53-66. 116 | -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/code/matlab/Asymmetry_AS.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 蚂蚁系统:非对称版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | %% 输出: 9 | % minimal_path:最短路径序列 10 | % minimal_length:最短路径长度 11 | %% --------------------------------------------------------------------%% 12 | function [minimal_path,minimal_length] = Asymmetry_AS(x,y,iterate_max) 13 | % 获取城市数目 14 | city_num = length(x); 15 | % 设置蚂蚁数目 16 | ants = 20; 17 | % 路径的相对重要性参数 18 | alpha = 1; 19 | % 能见度的相对重要性参数 20 | beta = 1; 21 | % 信息素持久性 22 | rho = 0.5; 23 | % 蚂蚁铺设的足迹数量相关的常数 24 | Q = 100; 25 | % 初始化各路径之间的信息素,对各路径赋予一个足够小的常数 26 | tau = ones(city_num) * 1e-5; 27 | % 各城市之间的距离 28 | distance = zeros(city_num); 29 | for i = 1:city_num 30 | for j = i+1:city_num 31 | distance(i,j) = sqrt((x(i)-x(j))^2+(y(i)-y(j))^2); 32 | distance(j,i) = distance(i,j); 33 | end 34 | end 35 | distance_diag = ones(1,city_num) .* 1e-5; 36 | distance_diag = diag(distance_diag); 37 | distance = distance_diag + distance; 38 | % 路径的能见度,使用距离的倒数 39 | eta = 1 ./ distance; 40 | % 记录最短路径 41 | minimal_path = zeros(1,city_num); 42 | % 记录最短路径的长度 43 | minimal_length = inf; 44 | 45 | iterate = 0; 46 | while iterate < iterate_max 47 | % 生成一个禁忌表,禁忌表大小为ants行,city_num列 48 | tabu = zeros(ants,city_num); 49 | % 将所有蚂蚁分布在不同的城市起点 50 | random_city = randperm(city_num); 51 | for i = 1:ants 52 | city_index = randperm(length(random_city),1); 53 | city = random_city(city_index); 54 | random_city(city_index) = []; 55 | tabu(i,city) = 1; 56 | end 57 | % 蚂蚁通过相应的公式选择对应路径进行移动,并求解对应蚂蚁走过的路径长度 58 | ants_track_length = zeros(1,ants); 59 | for i = 2:city_num 60 | for j = 1:ants 61 | allowed = find(tabu(j,:) == 0); 62 | start_city = find(tabu(j,:) == i-1); 63 | visited_probability = ((tau(start_city,allowed).^alpha) .* (eta(start_city,allowed).^beta)) ./ (sum((tau(start_city,allowed).^alpha) .* (eta(start_city,allowed).^beta))); 64 | visit_city_index = find(visited_probability == max(visited_probability),1); 65 | visit_city = allowed(visit_city_index); 66 | tabu(j,visit_city) = i; 67 | ants_track_length(j) = ants_track_length(j) + distance(tabu(j,:)==i-1,tabu(j,:)==i); 68 | end 69 | end 70 | for i = 1:ants 71 | ants_track_length(i) = ants_track_length(i) + distance(tabu(i,:)==city_num,tabu(i,:)==1); 72 | if min(ants_track_length) < minimal_length 73 | minimal_length = min(ants_track_length); 74 | minimal_path = tabu(find(ants_track_length == min(ants_track_length),1),:); 75 | end 76 | end 77 | % 求解对应蚂蚁所走过的路径上的信息素增量 78 | delta_tau = Q ./ ants_track_length; 79 | % 每次迭代时,信息素会挥发,信息素余量为 rho倍 80 | tau = rho .* tau; 81 | % 更新对应路径上的信息素 82 | for i = 1:ants 83 | for j = 2:city_num 84 | tau(tabu(i,:)==j-1,tabu(i,:)==j) = tau(tabu(i,:)==j-1,tabu(i,:)==j) + delta_tau(i); 85 | end 86 | tau(tabu(i,:)==city_num,tabu(i,:)==1) = tau(tabu(i,:)==city_num,tabu(i,:)==1) + delta_tau(i); 87 | end 88 | 89 | iterate = iterate + 1; 90 | end 91 | end 92 | 93 | -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/code/matlab/DrawPath.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 路径绘画函数 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | % minimal_path:最短路径序列 9 | %% --------------------------------------------------------------------%% 10 | function [] = DrawPath(x,y,minimal_path) 11 | % 画图,首先需要最短路径的对应城市访问顺序 12 | city_num = length(x); 13 | sequence_x = zeros(1,city_num+1); 14 | sequence_y = zeros(1,city_num+1); 15 | for i = 1:city_num 16 | city_index = find(minimal_path == i); 17 | sequence_x(i) = x(city_index); 18 | sequence_y(i) = y(city_index); 19 | end 20 | city_index = find(minimal_path == 1); 21 | sequence_x(city_num+1) = x(city_index); 22 | sequence_y(city_num+1) = y(city_index); 23 | % scatter(x,y,'k',"filled"); 24 | plot(sequence_x,sequence_y,'g-o','MarkerFaceColor','k'); 25 | end 26 | 27 | -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/code/matlab/Symmetry_AS.m: -------------------------------------------------------------------------------- 1 | %% =====================================================================%% 2 | %% 蚂蚁系统:对称版 3 | % coding:陈小斌 4 | % Github:doFighter 5 | %% 输入: 6 | % x: x轴坐标 7 | % y: y轴坐标 8 | %% 输出: 9 | % minimal_path:最短路径序列 10 | % minimal_length:最短路径长度 11 | %% --------------------------------------------------------------------%% 12 | function [minimal_path,minimal_length] = Symmetry_AS(x,y,iterate_max) 13 | % 获取城市数目 14 | city_num = length(x); 15 | % 设置蚂蚁数目 16 | ants = 20; 17 | % 路径的相对重要性参数 18 | alpha = 1; 19 | % 能见度的相对重要性参数 20 | beta = 1; 21 | % 信息素持久性 22 | rho = 0.5; 23 | % 蚂蚁铺设的足迹数量相关的常数 24 | Q = 100; 25 | % 初始化各路径之间的信息素,对各路径赋予一个足够小的常数 26 | tau = ones(city_num) * 1e-5; 27 | % 各城市之间的距离 28 | distance = zeros(city_num); 29 | for i = 1:city_num 30 | for j = i+1:city_num 31 | distance(i,j) = sqrt((x(i)-x(j))^2+(y(i)-y(j))^2); 32 | distance(j,i) = distance(i,j); 33 | end 34 | end 35 | distance_diag = ones(1,city_num) .* 1e-5; 36 | distance_diag = diag(distance_diag); 37 | distance = distance_diag + distance; 38 | % 路径的能见度,使用距离的倒数 39 | eta = 1 ./ distance; 40 | % 记录最短路径 41 | minimal_path = zeros(1,city_num); 42 | % 记录最短路径的长度 43 | minimal_length = inf; 44 | 45 | iterate = 0; 46 | while iterate < iterate_max 47 | % 生成一个禁忌表,禁忌表大小为ants行,city_num列 48 | tabu = zeros(ants,city_num); 49 | % 将所有蚂蚁分布在不同的城市起点 50 | random_city = randperm(city_num); 51 | for i = 1:ants 52 | city_index = randperm(length(random_city),1); 53 | city = random_city(city_index); 54 | random_city(city_index) = []; 55 | tabu(i,city) = 1; 56 | end 57 | % 蚂蚁通过相应的公式选择对应路径进行移动,并求解对应蚂蚁走过的路径长度 58 | ants_track_length = zeros(1,ants); 59 | for i = 2:city_num 60 | for j = 1:ants 61 | allowed = find(tabu(j,:) == 0); 62 | start_city = find(tabu(j,:) == i-1); 63 | visited_probability = ((tau(start_city,allowed).^alpha) .* (eta(start_city,allowed).^beta)) ./ (sum((tau(start_city,allowed).^alpha) .* (eta(start_city,allowed).^beta))); 64 | visit_city_index = find(visited_probability == max(visited_probability),1); 65 | visit_city = allowed(visit_city_index); 66 | tabu(j,visit_city) = i; 67 | ants_track_length(j) = ants_track_length(j) + distance(tabu(j,:)==i-1,tabu(j,:)==i); 68 | end 69 | end 70 | for i = 1:ants 71 | ants_track_length(i) = ants_track_length(i) + distance(tabu(i,:)==city_num,tabu(i,:)==1); 72 | if min(ants_track_length) < minimal_length 73 | minimal_length = min(ants_track_length); 74 | minimal_path = tabu(find(ants_track_length == min(ants_track_length),1),:); 75 | end 76 | end 77 | % 求解对应蚂蚁所走过的路径上的信息素增量 78 | delta_tau = Q ./ ants_track_length; 79 | % 每次迭代时,信息素会挥发,信息素余量为 rho倍 80 | tau = rho .* tau; 81 | % 更新对应路径上的信息素 82 | for i = 1:ants 83 | for j = 2:city_num 84 | tau(tabu(i,:)==j-1,tabu(i,:)==j) = tau(tabu(i,:)==j-1,tabu(i,:)==j) + delta_tau(i); 85 | tau(tabu(i,:)==j,tabu(i,:)==j-1) = tau(tabu(i,:)==j-1,tabu(i,:)==j); 86 | end 87 | tau(tabu(i,:)==city_num,tabu(i,:)==1) = tau(tabu(i,:)==city_num,tabu(i,:)==1) + delta_tau(i); 88 | tau(tabu(i,:)==1,tabu(i,:)==city_num) = tau(tabu(i,:)==city_num,tabu(i,:)==1); 89 | end 90 | 91 | iterate = iterate + 1; 92 | end 93 | end 94 | 95 | -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/images/AS-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/蚁群优化算法/蚂蚁系统/images/AS-1.jpg -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/images/AS-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/蚁群优化算法/蚂蚁系统/images/AS-2.jpg -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/images/AS-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/蚁群优化算法/蚂蚁系统/images/AS-3.jpg -------------------------------------------------------------------------------- /蚁群优化算法/蚂蚁系统/蚂蚁系统.md: -------------------------------------------------------------------------------- 1 | # 蚂蚁系统(Ant System,AS) 2 | 3 | ## 1. 摘要 4 | 5 | 通过对蚁群运作方式的类比 $Dorigo$ 等人提出了一种新的计算范式的定义,并将其称之为蚂蚁系统($AS$)。该优化算法可作为一种可行的随机组合优化新方法。 6 | 7 | 该模型的主要特征: 8 | 9 | - 正反馈 10 | - 分布式计算 11 | - 使用建设性贪婪启发式算法 12 | 13 | 在该算法中,正反馈有助于快速发现好的解决方案,分布式计算避免过早收敛,贪婪启发式有助于在搜索过程的早期阶段找到可接受的解决方案。 14 | 15 | 应用场景: 16 | 17 | 1. 非对称式旅行商问题 18 | 2. 二次分配问题 19 | 3. 车间作业调度问题 20 | 21 | ## 2. 算法描述 22 | 23 | ### 2.1 算法起源 24 | 25 | 在本文描述的蚂蚁系统,是指将要解决问题的搜索活动分配给所谓的“蚂蚁”,即具有非常简单的基本能力的代理,在某种程度上模仿真实蚂蚁的行为。 26 | 27 | 动物行为学家研究蚂蚁这类几乎失明的动物如何设法建立从它们的殖民地到觅食来源并返回的最短路线。从中发现用于在个人之间传达有关路径的信息并用于决定去哪里的媒体由信息素轨迹组成。一只移动的蚂蚁在地面上放置一些信息素(数量不同),从而通过这种物质的踪迹标记路径。虽然孤立的蚂蚁基本上是随机移动的,但遇到先前铺设的踪迹的蚂蚁可以检测到它并决定跟随它的可能性很高,从而用自己的信息素加强踪迹。出现的集体行为是自催化行为的一种形式,其中蚂蚁跟随的越多,跟踪的吸引力就越大。因此,该过程以正反馈循环为特征,其中蚂蚁选择路径的概率随着先前选择相同路径的蚂蚁数量而增加。 28 | 29 | ![ref](images/AS-1.jpg) 30 | 31 | 例如,考虑图 1 中所示的实验设置。有一条蚂蚁觅食行走的路径(例如,从食物源 A 到巢穴 E,反之亦然,见图 1a)。 32 | 33 | 当路径被一个障碍物切断时,蚂蚁在位置 B必须做出一个选择,是选择路线 $B\Rightarrow C \Rightarrow D \Rightarrow E$,还是选择路线 $B\Rightarrow H \Rightarrow D \Rightarrow E$(从 $E \Rightarrow A $亦是如此)(图 1b)。同时蚂蚁做选择也会受前面蚂蚁留下的信息素踪迹强度的影响。正确路径上更高水平的信息素会给蚂蚁带来更强的刺激,因此向右转的可能性更高。第一个到达点 B(或 D)的蚂蚁向右或向左转的概率相同(因为在两条替代路径上没有先前的信息素)。因为路径 BCD 比 BHD 短,跟随它的第一只蚂蚁将在跟随路径 BHD 的第一只蚂蚁之前到达 D(图 1c)。结果是一只从 E 返回到 D 的蚂蚁将在路径 DCB 上找到一条更强的踪迹,这是由于所有蚂蚁中有一半偶然决定通过 DCBA 接近障碍物,而已经到达的蚂蚁通过 BCD 到达:它们将因此(在概率上)更喜欢路径 DCB 到路径 DHB。因此,单位时间内跟随路径 BCD 的蚂蚁数量将高于跟随 BHD 的蚂蚁数量。这导致较短路径上的信息素数量比较长路径上的增长速度更快,因此任何一只蚂蚁选择要遵循的路径的概率很快就会偏向较短的路径。最终的结果是很快所有蚂蚁都会选择较短的路径。 34 | 35 | >- 为了进一步解释,作者还通过使用控制变量的方式举例,如下所述: 36 | 37 | 在不考虑其他条件情形下,由$B\Rightarrow H\Rightarrow D$(反之亦然)的距离 $d = 2$,而$B\Rightarrow C\Rightarrow D$的距离为 $d = 1$,即 $B\Rightarrow H\Rightarrow D$(接下来称为路线1) 路线的长度是 $B\Rightarrow C\Rightarrow D$(接下来称为路线2) 的两倍,因此在控制时间变量的情况下,蚂蚁走一遍路线1的时间内可以使蚂蚁走两遍路线2。假设所有蚂蚁信息素释放速率一样,则路线2在相同时间内的信息素的量会是路线1的两倍,同时,蚂蚁选择路线会受信息素的影响,按照朴素的方法进行计算,则下次选择路线2的蚂蚁会是选择路线1的蚂蚁的两倍,按照此种方式,最后所有蚂蚁将会全部选择路线2. 38 | 39 | 当然,为了方便理解与描述,上述过程并未加入信息素蒸发的操作。同时也将 $A\Rightarrow B$ 与 $D\Rightarrow E$ 的距离忽略不计,但是上述描述会非常简单,个人感觉这样会更加便于理解。 40 | 41 | 另外一个需要注意的是,在上述描述中,每次蚂蚁去与回都会走相同路径。 42 | 43 | ![ref](images/AS-2.jpg) 44 | 45 | ### 2.2 与真实蚁群的区别 46 | 47 | - 人造蚂蚁将具有一定的记忆力 48 | - 它们不会完全失明 49 | - 它们将生活在时间离散的环境中 50 | 51 | ### 2.3 主要特征 52 | 53 | - **通用性:** 它可以应用于同一问题的类似版本; 例如,旅行商问题 (TSP) 可以直接扩展到非对称旅行商问题 (ATSP)。 54 | - **鲁棒性:** 它可以应用于其他组合优化问题,例如二次分配问题 (QAP) 和作业车间调度问题 (JSP),只需进行最小的更改。 55 | - **基于种群的组合优化方法:** 它允许利用正反馈作为搜索机制,它还使系统适合并行实现。 56 | 57 | ## 3 算法实现 58 | 59 | 在算法实现中,本文以经典的旅行商问题为例,在该问题中,我们对蚂蚁有约定: 60 | 61 | 1. 它选择要去的城镇的概率是城镇距离和连接边上存在的路径数量的函数; 62 | 2. 两城市之间的路径长度取两城市之间的欧式距离; 63 | 3. 强制蚂蚁进行合法的旅行,在旅行完成之前不允许转换到已经访问过的城镇(这由禁忌列表控制); 64 | 4. 当它完成一次巡视时,它会在每条被访问的边 $(i,j)$ 上放置一个叫做 $trail$(可被称为 信息素) 的物质。 65 | 66 | ### 3.1 信息素更新 67 | 68 | 令 $τ_{ij}(t)$ 为 $t$ 时刻边缘 $(i,j)$ 上的信息素强度。 每只蚂蚁在时间 $t$ 选择下一个城镇,它在时间 $t+1$ 时到达城镇。 因此,如果我们将 $AS$ 算法的一次迭代称为 $m$ 只蚂蚁在区间 $(t, t+1)$ 中进行的 $m$ 次移动,那么算法的每 $n$ 次迭代(我们称之为循环)每只蚂蚁都完成了一次 旅游。 此时轨迹强度根据以下公式更新: 69 | 70 | $$ 71 | τ_{ij}(t+n) = \rho \cdot τ_{ij}(t)+\Delta τ_{ij}\tag{1} 72 | $$ 73 | 74 | > 其中 $\rho$ 指代信息素在 $t$ 到 $t+n$ 时间内剩余比例,即信息素在 $t$ 到 $t+n$ 时间内蒸发率为 $(1-\rho)$。 75 | 76 | $$ 77 | \Delta τ_{ij} = \sum_{k=1}^m\Delta τ_{ij}^k\tag{2} 78 | $$ 79 | 80 | > 其中 $\Delta τ_{ij}$ 是指所有在 $t$ 到 $t+n$ 时间内经过路径 $(i,j)$ 蚂蚁释放信息素的总和。 81 | 82 | $$ 83 | \Delta τ_{ij}^k = \begin{cases} 84 | \frac{Q}{L_k}&当第 k 只蚂蚁在时间t到t+n之间经过路径(i,j)\\ 85 | 0&当蚂蚁没走过路径(i,j) 86 | \end{cases}\tag{3} 87 | $$ 88 | 89 | > 其中 $Q$ 是一个常数,$L_k$ 为第 $k$ 只蚂蚁的旅行路径长度。 90 | 91 | - 在上面的内容中,需要特别注意以下几点: 92 | 1. $\rho$ 的值需要小于 1,否则信息素会不断累加,即信息素一定会有蒸发。 93 | 2. 在实验开始时,即蚂蚁还未开始旅行时,通常会将路径$(i,j)$信息素浓度设置为一个足够小的常数 $c$。 94 | 95 | >注意:在这里有一个问题需要进行说明,那就是信息素更新。本文作者认为,当解决的问题是非对称问题时,信息素更新时路径 $(i,j)$ 与 $(j,i)$ 是不一样的,只需要单独更新蚂蚁所走的路线;当问题为对称时,由于路径 $(i,j)$ 与 $(j,i)$ 两者是一致的,因此更新其中一个位置的信息素时,另一个位置的信息素也同时更新。 96 | 此外,当是非对称问题时,那么相应的非对称距离也是提前准备好的。 97 | 98 | ### 3.2 路径唯一性约束 99 | 100 | 为了满足在路途路线上不会重复到达某个城市,在蚂蚁旅行时使用了禁忌表,该表负责记录对应蚂蚁已经经过的路线,并且确保蚂蚁在接下来的搜索时不会再次经过该路径。 101 | 102 | - 禁忌表执行以下操作 103 | 1. 保存在时间 $t$ 之前已经访问过的城镇,并禁止蚂蚁在 $n$ 次迭代之前再次访问它们 (游览)已完成。 104 | 2. 当游览完成时,禁忌列表用于计算蚂蚁的当前解决方案(即蚂蚁所遵循的路径的距离)。 然后禁忌列表被清空,蚂蚁可以再次自由选择。 105 | 3. 我们定义 $tabu_k$ 是动态增长的向量,它包含第 $k$ 只蚂蚁的禁忌列表,$tabu_k$ 是从 $tabu_k$ 的元素获得的集合,$tabu_k(s)$ 是列表的第 $s$ 个元素(即被访问过的第 $s$ 个城镇) 当前巡演中的第 $k$ 只蚂蚁)。 106 | > 禁忌表 $tabu_k$ 不一定是动态增长的向量,一般动态增长增长的向量在运行时需要耗费更多的时间给它分配空间,并且在该算法中,是可以提前了解到禁忌表的大小,因此可以在一开始就分配好禁忌表的空间。 107 | 108 | 在禁忌表的控制下,第 $k$ 只蚂蚁的从城市 $i$ 转移到 $j$ 的概率为: 109 | $$ 110 | p_{ij}^k(t)=\begin{cases} 111 | \frac{[τ_{ij}(t)]^\alpha\cdot[\eta_{ij}]^\beta}{\sum_{s\in allowed_i^k}[τ_{is}(t)]^\alpha\cdot[\eta_{is}]^\beta}&if\; j\in allowed_i^k\\ 112 | 0&otherwise 113 | \end{cases}\tag{4} 114 | $$ 115 | > 116 | > 1. 其中称 $η_{ij}$ 为能见度,其值取 $1/d_{ij}$,且该值在算法运行期间不会被修改。 117 | > 118 | > 2. 其中$allowed_i^k = {N - tabu_i^k}$,指除去第 $k$ 只蚂蚁已经走过的城市,即第 $k$ 只蚂蚁的禁忌表中含有的城市,更简单的记法,可以记作第 $k$ 只蚂蚁所在城市 $i$ 还能访问的城市集合。其中 α 和 β 是控制轨迹与可见性的相对重要性的参数。 因此,转移概率是可见性(表示应该以高概率选择附近城镇,从而实施贪婪的建设性启发式)和时间 $t$ 的路径强度(表示直到时间 $t$ 如果在路径 $(i,j)$ 上有了更多的信息素累积,那么它是非常可取的,因此实现了自催化过程)。 119 | 120 | ### 3.3 蚁群算法执行定义 121 | 122 | 1. 在时间 0 处执行算法初始化,在此时将各蚂蚁置于不同的起点城市,并将各路径上的信息素设置为初始值 $τij(0)$。 123 | 2. 每只蚂蚁的禁忌表中第一个元素设置为它的起始城镇。 124 | 3. 此后每次移动到下一城镇,都需要根据公式 (4) 进行概率度量,选择概率最大的城镇移动,再执行移动操作后需要将该城市加入禁忌表。 125 | 4. 按照3.1中的信息素更新方式进行路径上的信息素更新。 126 | 5. 当遍历完所有城市,将禁忌表清空,执行下一次循环(只是将禁忌表清空)。 127 | 128 | > 1. $τ_{ij}(t)$ 给出了过去有多少蚂蚁选择了同一条边 $(i,j)$ 的信息; 129 | > 2. 能见度 $η_{ij}$,表示一个城镇越近,它就越受欢迎。 显然,设置 $α=0$,不再考虑信息素的影响,就会得到一个多起点的随机贪心算法。 130 | 131 | - 算法停止搜索条件: 132 | 1.算法的迭代次数达到了我们设定的最大迭代次数 133 | 2.算法中的蚂蚁全部都选择同一路径,也就是陷入停滞 134 | 135 | >一般来说会采取第一种,设置一个最大迭代次数。当然,也或许可以有第三种算法停止搜索的条件,当达到求解的精度,比如设定一个最短路径可接受的范围,当达到该标准就停止迭代,算法终止。 136 | 137 | ### 3.4 蚂蚁系统流程 138 | 139 | **1. 初始化** 140 | $ 141 | 1.1\quad Set\;t:=0\qquad t 是时间计数器\\ 142 | 1.2\quad Set\;NC:=0\qquad NC 是迭代次数计数器\\ 143 | 1.3\quad 对每一条路径(i,j)设置一个信息素初始值τ_{ij}(0)=c并且设置对应路径信息素增量为0:\Delta τ_{ij}^k=0\\ 144 | 1.4\quad 将所有蚂蚁分配到不同的起始城市 145 | $ 146 | **2. 禁忌表初始化** 147 | $ 148 | 2.1\quad Set\;s:=1\qquad s是禁忌表的索引\\ 149 | 2.2\quad 将各蚂蚁的起点城市放置到对应蚂蚁的禁忌表中。 150 | $ 151 | **3. 蚂蚁巡游操作** 152 | $ 153 | 3.1\quad 使用对应的公式进行蚂蚁巡游操作,直至禁忌表空间满,即所有蚂蚁全部走完所有城市。在每次走到一座城市时都需要及时的将该城市加入禁忌表中。 154 | $ 155 | **4. 最短路径更新及信息素增量计算** 156 | $ 157 | 4.1\quad 将各蚂蚁的出发点与终点相连,形成一个闭环,并计算所有蚂蚁线路的长度,并更新最短的路线。\\ 158 | 4.2\quad 对每只蚂蚁巡游过的路线进行信息素增量计算,计算公式如下:\\ 159 | \Delta τ_{ij}^k = \begin{cases} 160 | \frac{Q}{L_k}&当路径(i,j)在巡游路线中\\ 161 | 0&当蚂蚁没走过路径(i,j) 162 | \end{cases}\\ 163 | \Delta τ_{ij}:=\Delta τ_{ij}+\Delta τ_{ij}^k 164 | $ 165 | **5. 对路径进行信息素更新** 166 | $ 167 | 5.1\quad 对路径(i,j)计算当前信息素τ_{ij}(t+n),按照公式:τ_{ij}(t+n)=\rho \cdot τ_{ij}(t)+\Delta τ_{ij}\\ 168 | 5.2\quad Set\;t:=t+n\\ 169 | 5.3\quad Set\;NC:=NC+1\\ 170 | 5.4\quad 将路径(i,j)的信息素增量设置为0,\Delta τ_{ij}=0 171 | $ 172 | **6. 迭代条件判断** 173 | $ 174 | 6.1\quad 判断迭代次数NC是否小于最大允许迭代次数NC_{max},如果是,则清空禁忌表,返回第二步,否则输出最短路径,算法终止。 175 | $ 176 | 177 | - 原文算法流程如下所示: 178 | ![ref](images/AS-3.jpg) 179 | 180 | ## 4 参数设置及基本含义 181 | 182 | • α:路径的相对重要性,α≥0; 183 | • β:能见度的相对重要性,β≥0; 184 | • ρ:信息素持久性,0≤ρ<1(1-ρ 可以解释为信息素蒸发率); 185 | • Q:与蚂蚁铺设的足迹数量相关的常数。 186 | 187 | 在经过作者的大量测试后,提供了以下相关参数设置 188 | 189 | 1. 蚂蚁的数量 m 一般被设置为等于城市的数量 n。 190 | 2. 参数的默认值为α=1、β=1、ρ=0.5、Q=100。 191 | 192 | >蚂蚁循环中的最优值 ρ = 0.5 可以解释为,该算法在计算的早期阶段使用贪婪启发式引导搜索后,开始利用包含在 trail 值 τij 中的全局信息。 因此,Ant-cycle 需要有可能忘记过去获得的部分经验,以便更好地利用新传入的全球信息。 193 | 194 | ## 5 代码编写 195 | 196 | ## 6 参考文献 197 | 198 | [1] Dorigo M , Maniezzo V . Ant system: optimization by a colony of cooperating agents[J]. IEEE Trans. on SMC-Part B, 1996, 26(1):29. 199 | -------------------------------------------------------------------------------- /遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-1.png -------------------------------------------------------------------------------- /遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-2.png -------------------------------------------------------------------------------- /遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-3.png -------------------------------------------------------------------------------- /遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-4.png -------------------------------------------------------------------------------- /遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/多目标遗传算法-(NSGA-Ⅱ)/images/NSGA-Ⅱ-5.png -------------------------------------------------------------------------------- /遗传算法/多目标遗传算法-(NSGA-Ⅱ)/精英非支配排序遗传算法-(NSGAⅡ).md: -------------------------------------------------------------------------------- 1 | # 精英非支配排序遗传算法(ELITIST NONDOMINATED SORTING GENETIC ALGORITHM,NSGA-Ⅱ) 2 | 3 | ## 1 引言 4 | 5 | 在文献[1]中,作者提出了一种基于非支配排序的多目标进化算法(MOEA),称为非支配排序遗传算法 II (NSGA-II),它缓解了进化算法以下三个困难: 6 | 7 | 1. 时间复杂度为$O(MN^3)$,其中$M$为求解目标数,$N$为种群数目 8 | 2. 非精英主义方法 9 | 3. 需要指定共享参数 10 | 11 | 具体来说,提出了一种计算复杂度为$O(MN^2)$的快速非支配排序方法。此外,还提出了一个选择算子,它通过结合父母和后代种群并选择最佳(关于适应度和传播)解决方案来创建交配池。对困难测试问题的仿真结果表明,与 Pareto 归档进化策略和强度 Pareto EA 相比,在大多数问题中,所提出的 NSGA-II 能够在真正的 Pareto 最优前沿附近找到更好的解分布和更好的收敛性——另外两个精英 MOEAs 特别关注创造一个多样化的帕累托最优前沿。 12 | 13 | 原则上,一个问题中存在多个目标会产生一组最优解(主要是称为帕累托最优解),而不是单个最优解。 在没有任何进一步信息的情况下,不能说这些帕累托最优解中的一个比另一个更好。 这要求用户找到尽可能多的帕累托最优解。 经典优化方法(包括多准则决策方法)建议通过一次强调一个特定的帕累托最优解将多目标优化问题转换为单目标优化问题。 当这种方法用于寻找多个解决方案时,必须多次应用,希望在每次模拟运行时找到不同的解决方案。 14 | 15 | 在过去几十年中,已经提出了许多多目标进化算法 (MOEA)。由于进化算法 (EA) 与大量解决方案一起工作,因此可以扩展一个简单的 EA 以维护一组不同的解决方案。 强调向真正的帕累托最优区域移动,EA 可用于在一次模拟运行中找到多个帕累托最优解。 16 | 17 | N. Srinivas,Kalyanmoy Deb提出的非支配排序遗传算法 (NSGA) 是最早的此类 EA 之一。 多年来,对 NSGA 方法的主要批评如下: 18 | 19 | 1. 非支配排序计算复杂度高:NSGA非支配排序算法的计算复杂度为$O(MN^3)$(其中$M$为目标数,$N$为种群规模)。 这使得NSGA 对于大种群规模的计算成本很高。 之所以会出现这种大的复杂性,是因为每一代的非支配排序过程都涉及到复杂性。 20 | 2. 缺乏精英主义:最近的研究结果表明,精英主义可以显着加快 GA 的性能,这也有助于防止一旦找到好的解决方案就丢失。 21 | 3. 需要指定共享参数$\delta_{share}$:确保种群多样性以得到多种等效解决方案的传统机制主要依赖于共享的概念。 共享的主要问题是它需要指定共享参数($\delta_{share}$)。 22 | 23 | 本文的NSGA-Ⅱ解决了所有这些问题。 从对许多困难测试问题的模拟结果来看,我们发现 NSGA-II 在寻找多样化集合方面优于其他两个当代 MOEA:帕累托存档进化策略 (PAES)和强度帕累托 EA (SPEA)的解决方案,并在真正的帕累托最优集附近收敛。 24 | 25 | ## 2 算法介绍 26 | 27 | ### 2.1 快速非支配排序方法 28 | 29 | 为了清楚起见,作者首先描述了一个简单而缓慢的过程,将搜索代理分类为不同的非支配级别。 此后,作者描述了一种快速方法。 30 | 31 | 在一种朴素的方法中,为了识别大小为 $N$ 的种群中第一个非支配前沿的解,可以将每个解与种群中的所有其他解进行比较,以确定它是否被支配。这需要对每个解决方案进行 $O(MN)$ 比较,其中 $M$ 是目标的数量。当这个过程继续寻找种群中第一非支配层的所有成员时,总复杂度为$O(MN^2)$。在这个阶段,第一非支配前沿的所有个体都被找到。为了找到下一个非支配前沿的个体,将第一个前沿的解暂时忽略,重复上述过程。在最坏的情况下,找到第二前沿的任务也需要 $O(MN^2)$ 计算,特别是当 $O(N)$ 数量的解决方案属于第二和更高的非支配水平时。这个论点适用于寻找第三和更高层次的非支配。因此,最坏的情况是当有 $N$ 个前沿并且每个前沿仅存在一个解决方案时。这需要总体 $O(MN^3)$ 计算。请注意,此过程需要 $O(N)$ 存储。在下面的段落和方程式中,作者描述了一种需要 $O(MN^2)$ 计算的快速非支配排序方法。 32 | 33 | 首先,对于每个解决方案,需要计算两个实体: 34 | 35 | - 支配计数$n_p$,支配解决方案 $p$ 的数量 36 | - $S_p$,解决方案 $p$ 支配的一组解决方案。 37 | 38 | 这需要 $O(mn^2)$ 比较。 39 | 40 | 第一个非支配前沿中的所有解决方案都将其支配计数设为零。现在,对于 $n_p=0$ 的每个解 $p$,我们访问其集合 $S_p$ 的每个成员($q$),并将其支配计数减一。 这样做时,如果任何成员 $q$ 的支配计数变为零,我们将其放在单独的列表 $Q$ 中。这些成员属于第二非支配前沿。现在,对 $Q$ 的每个成员继续上述过程,并确定第三条前沿。 这个过程一直持续到所有前沿都被确定为止。 41 | 42 | 对于第二或更高非支配级别的每个解决方案,支配计数 $n_p$ 最多可以是 $N-1$。因此,每个解决方案 $p$ 在其支配计数变为零之前将被访问最多 $N-1$ 次。此时,该解决方案被分配一个非支配级别,并且永远不会再被访问。由于最多有 $N-1$ 个这样的解,总复杂度为 $O(N^2)$。因此,整个过程的复杂度为 $O(MN^2)$。计算这个复杂度的另一种方法是实现第一个内循环的主体(其中$p\in F_i$)精确执行 $N$ 次,因为每个个体最多可以是一个边沿的成员,并且第二个内部循环(对于$S_p$中的每个 $q$)可以对每个个体执行最多 $(N-1)$ 次[每个个体最多支配 $(N-1)$ 个个体,并且每个支配检查最多需要 $M$ 次比较] 导致总体 $O(MN^2)$ 计算。需要注意的是,虽然时间复杂度降低到了$O(MN^2)$,但是存储需求却增加到了$O(N^2)$。 43 | 44 | 快速非支配排序伪代码如下图所示: 45 | ![ref](images/NSGA-Ⅱ-2.png) 46 | 47 | ### 2.2 多样性保护 48 | 49 | 我们之前提到,随着收敛到帕累托最优集,还希望 EA 在获得的解决方案集中保持良好的解决方案传播。 最初的 NSGA 使用众所周知的共享函数方法,该方法已被发现通过适当设置其相关参数来维持种群的可持续多样性。 共享函数方法涉及共享参数 $\delta_{share}$,它设置问题中所需的共享程度。 此参数与选择用于计算两个总体成员之间的邻近度度量的距离度量有关。 参数 $\delta_{share}$ 表示任何两个解决方案共享彼此适应度的距离度量的最大值。 此参数通常由用户设置,尽管存在一些指导原则。 50 | 51 | 这种共享函数方法以下两个困难: 52 | 53 | - 共享函数方法在维持解的传播方面的性能在很大程度上取决于所选的 $\delta_{share}$ 值。 54 | - 由于每个解决方案都必须与总体中的所有其他解决方案进行比较,因此共享函数方法的总体复杂度为$O(n^2)$。 55 | 56 | 在提出的 NSGA-II 中,我们将共享函数方法替换为拥挤比较方法,在一定程度上消除了上述两个困难。 新方法不需要任何用户定义的参数来维持种群成员之间的多样性。 此外,建议的方法具有更好的计算复杂度。 为了描述这种方法,我们首先定义一个密度估计度量,然后提出拥挤比较算子。 57 | 58 | --- 59 | - 1. 密度估计:为了估计总体中特定解决方案周围的解决方案密度,我们计算沿每个目标的该点两侧的两个点的平均距离。 这个量$i_{distance}$用作对使用最近邻居作为顶点形成的长方体周长的估计(称为拥挤距离)。 在图 1 中,第 $i$ 个解在其前面的拥挤距离(用实心圆圈标记)是长方体的平均边长(用虚线框表示)。 60 | ![ref](images/NSGA-Ⅱ-1.png) 61 | 拥挤距离计算需要根据每个目标函数值按数量级升序对总体进行排序。 此后,对于每个目标函数,边界解(具有最小和最大函数值的解)被分配一个无限距离值。 所有其他中间解都分配了一个距离值,该距离值等于两个相邻解的函数值的绝对归一化差。 使用其他目标函数继续该计算。 总体拥挤距离值计算为每个目标对应的各个距离值的总和。 在计算拥挤距离之前,对每个目标函数进行归一化。 页面底部显示的算法概述了非支配集 $I$ 中所有解的拥挤距离计算过程。 62 | 这里 $I[i]\cdot m$ 是指集合 $I$ 中第 $i$ 个个体的第 $m$ 个目标函数值,参数 $f_m^{max}$ 和 $f_m^{min}$ 是第 $m$ 个目标函数的最大值和最小值。 该过程的复杂性由排序算法控制。 由于涉及到最多 $n$ 个解的 $m$ 个独立排序(当所有种群成员都在一个前面 $I$ 时),所以上述算法具有 $O(mn\log{n})$ 计算复杂度。 63 | 在为集合 $I$ 中的所有人口成员分配了距离度量之后,我们可以比较两个解决方案与其他解决方案的接近程度。 在某种意义上,这个距离度量值较小的解决方案被其他解决方案更拥挤。 这正是我们在提议的拥挤比较算子中比较的,如下所述。 尽管图 1 说明了两个目标的拥挤距离计算,但该过程也适用于两个以上的目标。 64 | --- 65 | - 2. 拥挤比较算子:拥挤比较算子 ($\prec_n$) 将算法各个阶段的选择过程引导到均匀展开的帕累托最优前沿。 假设代理中的每个个体都有两个属性: 66 | - 非支配等级($i_{rank}$) 67 | - 拥挤距离($i_{distance}$) 68 | 我们现在将偏序$\prec_n$定义为: 69 | $$ 70 | i\prec_n j\quad if(i_{rank}j_{distance})) 72 | $$ 73 | 也就是说,在具有不同非支配等级的两个解决方案之间,我们更喜欢具有较低(更好)等级的解决方案。 否则,如果两个解决方案属于同一前沿,那么我们更喜欢位于不太拥挤区域的解决方案。 74 | 75 | 拥挤距离计算伪代码如下: 76 | ![ref](images/NSGA-Ⅱ-3.png) 77 | 78 | 有了这三个新的创新——一个快速的非支配排序过程、一个快速的拥挤距离估计过程和一个简单的拥挤比较算子,我们现在可以描述 NSGA-II 算法了。 79 | 80 | ### 2.3 算法主体 81 | 82 | 最初,创建一个随机父群体 $P_0$。 代理是根据非支配性排序的。 每个解决方案都被分配一个与其非支配级别相等的适应度(或等级)(1 是最佳级别,2 是次佳级别,依此类推)。 因此,假设适应度最小化。 首先,使用通常的二元锦标赛选择、重组和变异算子来创建大小为 $n$ 的后代种群 $Q_0$。由于通过将当前种群与先前找到的最佳非支配解进行比较来引入精英主义,因此在初始生成之后过程会有所不同。 我们首先描述所提出算法的第 $t$ 代,伪代码如下图所示: 83 | ![ref](images/NSGA-Ⅱ-4.png) 84 | 85 | 一步一步的过程表明 NSGA-II 算法简单明了。首先,形成一个组合种群 $R_t=P_t∪Q_t$。种群 $R_t$ 的大小为 $2N$。然后,根据非支配对种群 $R_t$ 进行排序。由于所有以前和当前的人口成员都包含在 $R_t$ 中,因此确保了精英主义。现在,属于最佳非支配集 $F_1$ 的解在组合种群中是最佳解,并且必须比组合种群中的任何其他解更加强调。如果 $F_1$ 的大小小于 $N$,我们肯定会选择集合 $F_1$ 的所有成员作为新种群 $P_{t+1}$。种群 $P_{t+1}$ 的其余成员按其排名顺序从后续的非支配前沿中选择。因此,接下来选择集合 $F_2$ 中的解,然后选择集合 $F_3$ 中的解,依此类推。继续此过程,直到无法容纳更多集合。假设集合 $F_1$ 是最后一个非支配集合,超出该集合不能容纳其他集合。一般来说,从 $F_1$ 到 $F_l$ 的所有集合中的解决方案的数量都会大于人口规模。为了精确选择 $N$ 个人口成员,我们使用拥挤比较算子 $\prec_n$ 对最后一个前 $F_l$ 的解决方案进行降序排序并选择填补所有人口空缺所需的最佳解决方案。 NSGA-II 程序也如图 2 所示。大小为 $N$ 的新种群 $P_{t+1}$ 现在用于选择、交叉和突变以创建大小为 $N$ 的新种群 $Q_{t+1}$。重要的是要注意,我们使用二元锦标赛选择算子,但选择标准现在基于拥挤比较算子 $\prec_n$。由于该算子需要总体中每个解决方案的秩和拥挤距离,我们在形成总体 $P_{t+1}$ 时计算这些数量,如上述算法所示。 86 | 87 | ![ref](images/NSGA-Ⅱ-5.png) 88 | 89 | 考虑整个算法的一次迭代的复杂性。 基本操作及其最坏情况的复杂性如下: 90 | 91 | - 非支配排序复杂度为:$O(M(2N)^2))$ 92 | - 拥挤距离分配复杂度:$O(M(2N)\log(2N))$ 93 | - $\prec_n$排序复杂度为:$O(2N\log(2N))$ 94 | 95 | 该算法的总体复杂度为$O(MN^2)$,由算法的非支配排序部分控制。 如果仔细执行,大小为 $2N$ 的完整种群不需要根据非支配排序。 一旦排序过程找到足够数量的前沿以在 $P_{t+1}$ 中有 $N$ 个成员,就没有理由继续排序过程。 96 | 97 | 通过使用拥挤比较程序引入非支配解决方案之间的多样性,该程序用于锦标赛选择和人口减少阶段。 由于解决方案与其拥挤距离(邻域中解决方案的密度度量)竞争,因此不需要额外的利基参数(例如 NSGA 中需要的 $\delta_{share}$)。 虽然拥挤距离是在目标函数空间中计算的,但如果需要的话,它也可以在参数空间中实现。 然而,在本研究中进行的所有模拟中,我们都使用了目标函数空间细分。 98 | 99 | ## 3 算法实现 100 | 101 | ## 4 参考文献 102 | 103 | [1] Deb K , Pratap A , Agarwal S , et al. A fast and elitist multiobjective genetic algorithm: NSGA-II[J]. IEEE Transactions on Evolutionary Computation, 2002, 6(2):182-197. 104 | -------------------------------------------------------------------------------- /遗传算法/经典遗传算法-GA/code/python/GA_CodingWithFloat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2022/7/18 15:44 4 | # @Author : doFighter 5 | import random 6 | import numpy as np 7 | 8 | def GA_CodingWithFloat(N, dim, x_min, x_max, iterate_max, fitness): 9 | """ 10 | Floating point coding:浮点型编码版本 11 | :param N:染色体种群数目 12 | :param dim:每条染色体携带基因数目,即问题求解维度 13 | :param x_min:搜索空间下限 14 | :param x_max:搜索空间上限 15 | :param iterate_max:最大迭代次数 16 | :param fitness:适应度函数 17 | :return: 18 | 1. 返回最优适应度值 19 | 2. 返回最优适应度位置 20 | """ 21 | # 初始化交叉概率Pc 22 | Pc = 0.8 23 | # 初始化突变概率Pm 24 | Pm = 0.18 25 | # 交叉因子 26 | Pa = 0.01 27 | # 一个极小值 28 | eta = 1e-4 29 | # 初始化染色体,染色体数量为N,染色体上的基因个数为dim 30 | DNAs = x_min + (x_max - x_min) * np.random.rand(N, dim) 31 | # 染色体基于下标 32 | GeneIndex = range(0, dim) 33 | # 初始化适应度保存空间 34 | fitnessValue = np.ones(N) 35 | # 1.进行适应度评价 36 | for i in range(N): 37 | fitnessValue[i] = fitness(DNAs[i, :]) 38 | # 开始进入主体循环 39 | iterate = 0 40 | while iterate < iterate_max: 41 | # 进行选择操作 42 | # 2 轮盘赌构建中间种群 43 | # 2.1 由于轮盘赌是根据概率进行的,当最优化问题求解的是最小值时,则概率并不是直接用适应度直接计算 44 | fitnessSum = max(fitnessValue) + eta 45 | probability = fitnessSum - fitnessValue 46 | probability = probability / sum(probability) 47 | probability = np.cumsum(probability) 48 | # 2.2 根据轮盘赌构建中间种群 49 | intermediatePopulation = np.zeros([N, dim]) 50 | for i in range(N): 51 | rd = np.random.rand() 52 | index = np.where(probability > rd) 53 | intermediatePopulation[i, :] = DNAs[index[0][0], :].copy() 54 | 55 | # 3 重组操作和变异操作(即交叉操作和突变操作) 56 | # 3.1 计算重组操作次数 57 | CrossoverNum = int(N / 2) 58 | DNAList = list(range(0, N)) 59 | for i in range(CrossoverNum): 60 | # 随机获取两个染色体 61 | CrossoverIndex = random.sample(DNAList, 2) 62 | # 在这里,染色体进行交叉时并不会重复选择 63 | for k in CrossoverIndex: 64 | DNAList.remove(k) 65 | 66 | if np.random.rand() < Pc: 67 | # 进行交换(两点式交换),由于python是浅拷贝,所以不需要再次变换 68 | DNA1 = intermediatePopulation[CrossoverIndex[0], :].copy() 69 | DNA2 = intermediatePopulation[CrossoverIndex[1], :].copy() 70 | intermediatePopulation[CrossoverIndex[0], :] = Pa * DNA2 + (1-Pa) * DNA1 71 | intermediatePopulation[CrossoverIndex[1], :] = Pa * DNA1 + (1-Pa) * DNA2 72 | 73 | 74 | # 进行变异操作 75 | for i in range(N): 76 | k = 0.8 77 | rd = np.random.rand() 78 | if rd < Pm: 79 | rd1 = round(np.random.rand()) 80 | if rd1 == 1: 81 | intermediatePopulation[i, :] = intermediatePopulation[i, :] + k * ( 82 | x_max - intermediatePopulation[i, :]) * np.random.rand() 83 | else: 84 | intermediatePopulation[i, :] = intermediatePopulation[i, :] - k * ( 85 | intermediatePopulation[i, :] - x_min) * np.random.rand() 86 | 87 | DNAs = intermediatePopulation.copy() 88 | 89 | # 进行适应度评价 90 | for i in range(N): 91 | fitnessValue[i] = fitness(DNAs[i, :]) 92 | 93 | iterate += 1 94 | optimalIndex = np.where(fitnessValue == min(fitnessValue)) 95 | return fitnessValue[optimalIndex[0][0]], DNAs[optimalIndex[0][0], :] 96 | 97 | 98 | if __name__ == "__main__": 99 | def Sphere(xx): 100 | """ 101 | Sphere Function 102 | :param xx: 疑似最优解 103 | :return:适应度值 104 | """ 105 | d = len(xx) 106 | ele_sum = 0 107 | for i in range(d): 108 | ele_sum += xx[i] ** 2 109 | return ele_sum 110 | 111 | 112 | # 函数测试 113 | [result, position] = GA_CodingWithFloat(20, 30, -10, 10, 1000, Sphere) 114 | print(result) 115 | print(position) 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /遗传算法/经典遗传算法-GA/images/GA-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/经典遗传算法-GA/images/GA-1.png -------------------------------------------------------------------------------- /遗传算法/经典遗传算法-GA/images/GA-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/经典遗传算法-GA/images/GA-2.png -------------------------------------------------------------------------------- /遗传算法/经典遗传算法-GA/images/GA-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/经典遗传算法-GA/images/GA-3.png -------------------------------------------------------------------------------- /遗传算法/经典遗传算法-GA/images/GA-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/遗传算法/经典遗传算法-GA/images/GA-4.png -------------------------------------------------------------------------------- /麻雀搜索算法/麻雀搜索算法SSA/code/matlab/SSA.m: -------------------------------------------------------------------------------- 1 | %% =============================================================================%% 2 | %% SSA:麻雀搜索算法 (doi:10.1080/21642583.2019.1708830) 3 | % coding:陈小斌 4 | % Encoding format:utf-8 5 | % :param N: 种群数目 6 | % :param dim: 求解维度 7 | % :param x_min: 各维度搜索下限 8 | % :param x_max: 各维度搜索上限 9 | % :param iterate_max: 最大迭代次数 10 | % :param fitness: 适应度评价函数 11 | % :return: 12 | % optimal_value: 对应评价函数最优适应度 13 | % optimal_site: 最优位置 14 | %% -----------------------------------------------------------------------------%% 15 | 16 | 17 | function [optimal_value, optimal_site] = SSA(N, dim, x_min, x_max, iterate_max, fitness) 18 | % 初始化麻雀位置 19 | x = x_min + (x_max - x_min) .* rand(N, dim); 20 | % 最小常数 21 | varepsilon = exp(-16); 22 | % 安全阈值 23 | ST = 0.8; 24 | % 生产者数量 25 | PD = int64(0.2 * N); 26 | % 侦察麻雀数量 27 | SD = int64(0.1 * N); 28 | % 存储各个体适应度值 29 | Fx = ones(N, 1); 30 | % 求解对应位置的适应度值 31 | for i = 1:N 32 | Fx(i) = fitness(x(i, :)); 33 | end 34 | 35 | % 初始化迭代起点 36 | iterate = 1; 37 | 38 | while iterate < iterate_max+1 39 | % 对适应度值进行排列并获取按照适应度从大到小的下标排列 40 | [~, Fx_range_index] = sort(Fx); 41 | % 获取当前全局最优位置 42 | x_best = x(Fx_range_index(1), :); 43 | f_g = Fx((Fx_range_index(1))); 44 | % 获取当前全局最差位置 45 | x_worst = x(Fx_range_index(N), :); 46 | f_w = Fx(Fx_range_index(N)); 47 | % 用于记录新位置 48 | x_new = x; 49 | % 按照论文算法框架图,所有生产者是统一执行位置更新,见公式(3) 50 | if rand() < ST 51 | for i =1:PD 52 | x_new(Fx_range_index(i), :) = x(Fx_range_index(i), :) .* exp(-Fx_range_index(i) ./ (rand(1, dim) .* iterate_max)); 53 | end 54 | else 55 | % 论文中的公式描述有点问题,前半部分描述的是指定了对应麻雀对应维度,即为标量,而后面乘的却又是向量,赋给的又是标量,因此在这里实现了两种写法 56 | % 在对Sphere函数测试中,发现第一种方式效果更好 57 | % 第一种:按照向量写法,即每个位置只有一个alpha 58 | x_new(Fx_range_index(1: PD), :) = x(Fx_range_index(1: PD), :) .* rand(PD, 1); 59 | % 第二种:按照标量写法,即每个位置的对应维度都有一个随机alpha 60 | %x_new(Fx_range_index(: PD), :) = x(Fx_range_index(: PD), :) .* np.random.random((PD, dim)); 61 | end 62 | 63 | % 拾取者位置更新,公式(4) 64 | for i =PD+1:N 65 | if Fx_range_index(i) > N/2 66 | % 公式(4)和公式(3)一样,Q应该是对应维度都不同 67 | x_new(Fx_range_index(i), :) = rand(1, dim) .* exp((x_worst - x(Fx_range_index(i), :))/(Fx_range_index(i)^2)); 68 | else 69 | % A表示一个1×d的矩阵,其中每个元素随机分配1或-1 70 | A = rand(1, dim); 71 | A(A>0.5) = 1; 72 | A(A<0.5) = -1; 73 | A_inv = A' * (1/(A * A')); 74 | x_new(Fx_range_index(i), :) = x_best + abs(x(Fx_range_index(i), :) - x_best) * A_inv; 75 | end 76 | end 77 | % 侦察麻雀更新,公式(5):需要说明的是,在原文中并未说明侦察麻雀是哪些,只是描述了占总数的10%~20%,原文选取10%。这里就直接按照索引进行更新 78 | for i = 1:SD 79 | f_i = fitness(x_new(i, :)); 80 | if f_i > f_g 81 | x_new(i, :) = x_best + rand(1, dim) .* abs(x_new(i, :) - x_best); 82 | elseif f_i == f_g 83 | k = -1 + rand() * 2; 84 | x_new(i, :) = x_new(i, :) + k .* (abs(x_new(i, :) - x_worst)./(f_i - f_w + varepsilon)); 85 | end 86 | end 87 | 88 | % 如果当前位置要好于历史位置,则更新 89 | for i = 1:N 90 | if fitness(x_new(i, :)) < fitness(x(i, :)) 91 | x(i, :) = x_new(i, :); 92 | end 93 | end 94 | 95 | % 对更新后的位置进行合法性检查 96 | x(xx_max) = x_max; 98 | % 求解对应位置的适应度值 99 | for i = 1:N 100 | Fx(i) = fitness(x(i, :)); 101 | end 102 | 103 | % 迭代器++ 104 | iterate = iterate + 1; 105 | end 106 | % 对适应度值进行排列并获取按照适应度从大到小的下标排列 107 | [~, Fx_range_index] = sort(Fx); 108 | % 获取当前最优解 109 | optimal_value = Fx(Fx_range_index(1)); 110 | % 获取当前全局最优位置 111 | optimal_site = x(Fx_range_index(1), :); 112 | end 113 | -------------------------------------------------------------------------------- /麻雀搜索算法/麻雀搜索算法SSA/code/python/SSA.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2022/1/11 21:34 4 | # @Author : 陈小斌 5 | # @Github : doFighter 6 | # @File : SSA.py 7 | # @Software: PyCharm 8 | 9 | import numpy as np 10 | 11 | 12 | def SSA(N, dim, x_min, x_max, iterate_max, fitness): 13 | """ 14 | SSA:麻雀搜索算法 doi:10.1080/21642583.2019.1708830 15 | :param N: 种群数目 16 | :param dim: 求解维度 17 | :param x_min: 各维度搜索下限 18 | :param x_max: 各维度搜索上限 19 | :param iterate_max: 最大迭代次数 20 | :param fitness: 适应度评价函数 21 | :return: 22 | Fx[Fx_range_index[0]]: 对应评价函数最优适应度 23 | x_best: 最优位置 24 | """ 25 | # 初始化麻雀位置 26 | x = x_min + (x_max - x_min) * np.random.random([N, dim]) 27 | # 最小常熟 28 | varepsilon = np.exp(-16) 29 | # 安全阈值 30 | ST = 0.8 31 | # 生产者数量 32 | PD = int(0.2 * N) 33 | # 侦察麻雀数量 34 | SD = int(0.1 * N) 35 | # 存储各个体适应度值 36 | Fx = np.ones([N, 1]) 37 | # 求解对应位置的适应度值 38 | for i in range(N): 39 | Fx[i] = fitness(x[i, :]) 40 | # 初始化迭代起点 41 | iterate = 0 42 | 43 | while iterate < iterate_max: 44 | 45 | # 对适应度值进行排列并获取按照适应度从大到小的下标排列 46 | range_list = sorted(enumerate(Fx), key=lambda Fx_zip: Fx_zip[1]) 47 | Fx_range_index = [ele[0] for ele in range_list] 48 | # 获取当前全局最优位置 49 | x_best = x[Fx_range_index[0], :].copy() 50 | f_g = Fx[[Fx_range_index[0]]] 51 | # 获取当前全局最差位置 52 | x_worst = x[Fx_range_index[N-1], :].copy() 53 | f_w = Fx[Fx_range_index[N-1]] 54 | # 用于记录新位置 55 | x_new = x.copy() 56 | # 按照论文算法框架图,所有生产者是统一执行位置更新,见公式(3) 57 | if np.random.rand() < ST: 58 | for i in range(PD): 59 | x_new[Fx_range_index[i], :] = x[Fx_range_index[i], :] * \ 60 | np.exp(-Fx_range_index[i] / 61 | (np.random.random([1, dim]) * iterate_max)) 62 | else: 63 | # 论文中的公式描述有点问题,前半部分描述的是指定了对应麻雀对应维度,即为标量,而后面乘的却又是向量,赋给的又是标量,因此在这里实现了两种写法 64 | # 在对Sphere函数测试中,发现第一种方式效果更好 65 | # 第一种:按照向量写法,即每个位置只有一个alpha 66 | x_new[Fx_range_index[: PD], :] = x[Fx_range_index[: PD], 67 | :] * np.random.random([PD, 1]) 68 | # 第二种:按照标量写法,即每个位置的对应维度都有一个随机alpha 69 | # x_new[Fx_range_index[: PD], :] = x[Fx_range_index[: PD], :] * np.random.random([PD, dim]) 70 | 71 | # 拾取者位置更新,公式(4) 72 | for i in range(PD, N): 73 | if Fx_range_index[i] > N/2: 74 | # 公式(4)和公式(3)一样,Q应该是对应维度都不同 75 | x_new[Fx_range_index[i], :] = np.random.random( 76 | [1, dim]) * np.exp((x_worst - x[Fx_range_index[i], :])/(Fx_range_index[i]**2)) 77 | else: 78 | A = np.array([np.random.choice([1, -1]) for i in range(dim)]) 79 | A_inv = np.dot(A.T, 1/np.dot(A, A.T)) 80 | x_new[Fx_range_index[i], :] = x_best + \ 81 | np.abs(x[Fx_range_index[i], :] - x_best) * A_inv 82 | 83 | # 侦察麻雀更新,公式(5):需要说明的是,在原文中并未说明侦察麻雀是哪些,只是描述了占总数的10%~20%,原文选取10%。这里就直接按照索引进行更新 84 | for i in range(SD): 85 | f_i = fitness(x_new[i, :]) 86 | if f_i > f_g: 87 | x_new[i, :] = x_best + \ 88 | np.random.random([1, dim]) * np.abs(x_new[i, :] - x_best) 89 | elif f_i == f_g: 90 | k = -1 + np.random.random() * 2 91 | x_new[i, :] = x_new[i, :] + k * \ 92 | (np.abs(x_new[i, :] - x_worst)/(f_i - f_w + varepsilon)) 93 | 94 | # 对当前位置进行检查,判断是否合法 95 | x[x > x_max] = x_max 96 | x[x < x_min] = x_min 97 | # 如果当前位置要好于历史位置,则更新 98 | for i in range(N): 99 | if fitness(x_new[i, :]) < fitness(x[i, :]): 100 | x[i, :] = x_new[i, :].copy() 101 | 102 | # 求解对应位置的适应度值 103 | for i in range(N): 104 | Fx[i] = fitness(x[i, :]) 105 | # 迭代器++ 106 | iterate = iterate + 1 107 | 108 | # 对适应度值进行排列并获取按照适应度从大到小的下标排列 109 | range_list = sorted(enumerate(Fx), key=lambda Fx_zip: Fx_zip[1]) 110 | Fx_range_index = [ele[0] for ele in range_list] 111 | # 获取当前全局最优位置 112 | x_best = x[Fx_range_index[0], :].copy() 113 | 114 | return Fx[Fx_range_index[0]], x_best 115 | 116 | 117 | def Sphere(xx): 118 | """ 119 | Sphere Function 120 | :param xx: 疑似最优解 121 | :return:适应度值 122 | """ 123 | d = len(xx) 124 | sum = 0 125 | for i in range(d): 126 | sum += xx[i] ** 2 127 | return sum 128 | 129 | 130 | # 函数测试 131 | for i in range(10): 132 | result, site = SSA(20, 30, -10, 10, 100, Sphere) 133 | print(result) 134 | print(site) 135 | -------------------------------------------------------------------------------- /麻雀搜索算法/麻雀搜索算法SSA/images/SSA-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doFighter/Computational-intelligence/a2de2f223ba412c1d80a4734d8562ad956194993/麻雀搜索算法/麻雀搜索算法SSA/images/SSA-1.png -------------------------------------------------------------------------------- /麻雀搜索算法/麻雀搜索算法SSA/麻雀搜索算法.md: -------------------------------------------------------------------------------- 1 | # 麻雀搜索算法(sparrow search algorithm,SSA) 2 | 3 | ## 1 引言 4 | 5 | 文献[1]旨在提出一种新的群体智能优化技术,称为麻雀搜索算法(SSA)。 该文的主要内容如下: 6 | 7 | 1. 一种新的SI技术,即SSA是受麻雀觅食和反捕食行为的启发而提出的; 8 | 2. 通过使用所提出的SSA,在一定程度上改进了优化搜索空间的探索和开发; 9 | 3. 所提出的 SSA 成功地应用于两个实际工程问题。 10 | 11 | ## 2 算法介绍 12 | 13 | ### 2.1 生物学特性 14 | 15 | 麻雀是常见的常驻鸟类。与许多其他小型鸟类相比,麻雀非常聪明,记忆力也很强。请注意,有两种不同类型的圈养麻雀,生产者和拾取者。生产者积极寻找食物来源,而拾荒者则通过生产者获取食物。此外,有证据表明,鸟类通常灵活地使用行为策略,并在生产和觅食之间切换。也可以说,为了寻找食物,麻雀通常使用**生产者**和**拾取者**的策略。 16 | 17 | 研究表明,个体会监控群体中其他麻雀的行为。同时,鸟群中的攻击者为了提高自身的捕食率,被用来竞争高摄入量同伴的食物资源。此外,个体的能量储备可能在麻雀选择不同的觅食策略时发挥重要作用,能量储备低的麻雀觅食更多。值得一提的是,位于种群边缘的鸟类更容易受到捕食者的攻击,并不断试图获得更好的位置。请注意,位于中心的动物可能会靠近它们的邻居,以尽量减少它们的危险区域。我们也知道,所有的麻雀都表现出对一切事物的好奇本能,同时它们也时刻保持警惕。例如,当一只鸟确实发现了捕食者时,一个或多个个体发出唧唧声,整个群体飞走。 18 | 19 | ### 2.2 数学模型与算法 20 | 21 | 为简单起见,作者将麻雀的以下行为理想化并制定了相应的规则。 22 | 23 | 1. 生产者通常具有高水平的能量储备,并为所有拾取者提供觅食区域或方向。 它负责确定可以找到丰富食物来源的区域。 能量储备的水平取决于对个体适应度值的评估。 24 | 2. 一旦麻雀发现捕食者,个体就会开始发出唧唧声作为警报信号。 当警报值大于安全阈值时,生产者需要将所有的拾荒者引导至安全区域。 25 | 3. 每只麻雀只要寻找更好的食物来源,都可以成为生产者,但生产者和觅食者在整个种群中的比例不变。 26 | 4. 能量较高的麻雀作为生产者。 几个饥饿的拾荒者更有可能飞到其他地方觅食以获得更多能量。 27 | 5. 淘宝追随能提供最好食物的生产者寻找食物。 与此同时,一些掠夺者可能会不断地监视生产者并争夺食物以增加自己的捕食率。 28 | 6. 群体边缘的麻雀在意识到危险时迅速向安全区域移动以获得更好的位置,而群体中间的麻雀则随机行走以接近他人。 29 | 30 | 在模拟实验中,需要使用虚拟麻雀来寻找食物。 与其他群智能优化算法一致,麻雀的位置可以用矩阵$X$表示: 31 | 32 | $$ 33 | X = \begin{bmatrix} 34 | x_1^1&x_1^2&\dotsb&x_1^d\\ 35 | x_2^1&x_2^2&\dotsb&x_2^d\\ 36 | \vdots&\vdots&\ddots&\vdots\\ 37 | x_n^1&x_n^2&\dotsb&x_n^d\\ 38 | \end{bmatrix}\tag{1} 39 | $$ 40 | 41 | >其中$n$是麻雀的数量,$d$表示要优化的变量的维度。 那么,所有麻雀的适应度值可以用如下向量表示: 42 | 43 | $$ 44 | F_x = \begin{bmatrix} 45 | f([x_1^1&x_1^2&\dotsb&x_1^d])\\ 46 | f([x_2^1&x_2^2&\dotsb&x_2^d])\\ 47 | &\cdots\\ 48 | f([x_n^1&x_n^2&\dotsb&x_n^d])\\ 49 | \end{bmatrix}\tag{2} 50 | $$ 51 | 52 | >其中$n$表示麻雀的数量,$F_X$中每一行的值代表麻雀个体的适应度值。 53 | 54 | #### 2.2.1 生产者 55 | 56 | 在$SSA$中,适应度值较高的生产者在搜索过程中优先获得食物。 此外,因为生产者负责寻找食物并指导整个人口的流动。 因此,生产者可以在比拾荒者更广泛的地方寻找食物。 根据规则(1)和(2),在每次迭代期间,生产者的位置更新如下: 57 | 58 | $$ 59 | X_{i,j}^{t+1}=\begin{cases} 60 | X_{i,j}^t\cdot e^{\frac{-i}{\alpha \cdot iter_{max}}};& if\quad R_2其中$t$表示当前迭代,$j = 1, 2, ... , d$。$X_{i,j}^t$表示迭代$t$时第$i$个麻雀的第$j$个维度的值。$iter_{max}$是一个迭代次数最多的常数。 $α ∈ (0, 1]$ 是一个随机数。$R_2 (R_2 ∈ [0, 1])$ 和 $ST (ST ∈ [0.5, 1.0])$ 分别表示警报值和安全阈值。$Q$ 是一个随机数,服从正态分布。$L$表示形式为$1×d$的矩阵,其中每个元素为1。 66 | 67 | 当$R_2 < ST$,表示周围没有掠食者时,生产者进入广域搜索模式。如果$R_2≥ST$,表示有麻雀发现 捕食者,所有麻雀都需要迅速飞到其他安全区域。 68 | 69 | #### 2.2.2 拾取者 70 | 71 | 至于拾取者,他们需要执行规则(4)和(5)。 如上所述,一些拾取者更频繁地监控生产者。 一旦他们发现生产者找到了好食物,他们就会立即离开现在的位置去争夺食物。 如果他们赢了,他们可以立即得到生产者的食物,否则他们继续执行规则(5)。 拾取者的位置更新公式描述如下: 72 | 73 | $$ 74 | X_{i,j}^{t+1}=\begin{cases} 75 | Q\cdot e^{\frac{X_{worst}^t-X_{i,j}^t}{i^2}} &if\quad i>\frac{n}{2}\\ 76 | X_P^{t+1}+|X_{i,j}^t-X_{p}^{t+1}|\cdot A^+\cdot L&otherwise 77 | \end{cases}\tag{4} 78 | $$ 79 | 80 | 其中$X_P$是生产者占据的最优位置。 $X_{worst}$ 表示当前全局最差的位置。 $A$表示一个$1×d$的矩阵,其中每个元素随机分配1或-1,并且$A^+ = A^T(AA^T)^{-1}$。 当 $i > n/2$ 时,表明适应度值较差的第 $i$ 个寻宝者最有可能挨饿。 81 | 在模拟实验中,假设这些意识到危险的麻雀占总种群的 10% 到 20%。 这些麻雀的初始位置是在种群中随机生成的。 根据规则(6),数学模型可表示为: 82 | 83 | $$ 84 | X_{i,j}^{t+1}=\begin{cases} 85 | X_{best}^t+\beta \cdot|X_{i,j}^t-X_{best}^t|&if\quad f_i>f_g\\ 86 | X_{i,j}^t+k\cdot (\frac{|X_{i,j}^t-X_{worst}^t|}{(f_i-f_w)+\varepsilon})&if\quad f_i=f_g 87 | \end{cases}\tag{5} 88 | $$ 89 | 90 | >其中$X_{best}$是当前全局最优位置。$β$作为步长控制参数,是随机数的正态分布,均值为0,方差为1。$K ∈ [-1, 1]$是一个随机数。 这里$f_i$是当前麻雀的适应度值。$f_g$和$f_w$分别是当前全局最佳和最差适应度值。$ε$是最小的常数,以避免零除误差。 91 | 92 | 为简单起见,当$f_i > f_g$时表明麻雀在群体的边缘。$X_{best}$代表种群中心的位置,并且在其周围是安全的。$f_i = f_g$表明处于种群中间的麻雀意识到了危险,需要靠近其他麻雀。$K$表示麻雀移动的方向,也是步长控制系数。 93 | 94 | ## 3 代码实现 95 | 96 | 麻雀搜索算法参数设置如下: 97 | 98 | - 安全阈值:$ST=0.8$ 99 | - 生产者:$PD=0.2\times N$ 100 | - 意识到危险的麻雀数目:$SD=0.1\times N$ 101 | 102 | >上面描述中的$N$为种群总数。 103 | 104 | 麻雀算法的伪代码框架如下图所示: 105 | ![ref](images/SSA-1.png) 106 | 107 | >在实现代码时,最后的侦察麻雀直接按照索引下标进行位置更新。 108 | 109 | ### 3.1 注意事项 110 | 111 | - 在实际测试时,发现存在最优解超出搜索区间范围的情况,因此为了使得求解更加准确稳定,还是应该加上搜索区域判定。 112 | 113 | >代码详情见code文件夹。 114 | 115 | ## 参考文献 116 | 117 | [1]Xue J, Shen B. A novel swarm intelligence optimization approach: sparrow search algorithm[J]. Systems Science & Control Engineering, 2020, 8(1): 22-34. 118 | --------------------------------------------------------------------------------