FA:萤火虫算法的改进及Python实现

FA标准算法的基础上,针对步长因子、最亮个体行为、吸引模型等对萤火虫算法进行改进

一、自适应步长因子

随着迭代次数的增加,步长因子自适应减小,使得刚开始萤火虫更注重全局探索,而后则注重局部探索。

在python实现时,需要注意浅复制的问题!!!

(1)

    def alphat(self, t):
        self.alpha = (1 - t/self.T) * self.alpha  #自适应步长

(2)

    def alphat(self):
        self.alpha = 0.99 * self.alpha

(3)

    def alphat3(self, t):
        self.alpha = np.exp(-t/self.T) * self.alpha  #自适应步长

二、最亮个体行为

在每轮迭代中,所有个体都会向着最亮个体飞行,这会导致最亮个体不会更新,直到有其他更亮的个体出现。因此,我们为最亮个体增加新的行为:向周围试探飞行,如果适应度改善,则飞到新的位置,否则保持在原来的位置。

(1)仅扰动一次

    def FindNewBest(self, i):
        FFi = self.FitnessFunction(self.X[i,:])
        x_ = self.X[i, :] + self.alpha * (np.random.rand(self.D) - 0.5)
        ffi = self.FitnessFunction(x_)
        if ffi < FFi:
            self.X[i,:] = x_
            self.FitnessValue[i] = ffi

(2)扰动N次,相当于其他粒子能最优更新N次一样

    def FindNewBest(self, i):
        FFi = self.FitnessFunction(self.X[i,:])
        for i in range(self.N):
            x_ = self.X[i, :] + self.alpha * (np.random.rand(self.D) - 0.5)
            ffi = self.FitnessFunction(x_)
            if ffi < FFi:
                self.X[i,:] = x_
                self.FitnessValue[i] = ffi

可以看到,在发挥最优个体的局部探索作用后,效果出乎意料的好。同时,通过实验发现,扰动一次不仅所耗时间减少11.4%,解也更加稳定。

 

三、改进吸引模型

在标准萤火虫算法中,每只萤火虫是可以被群体中所有萤火虫吸引的,这种全吸引模型,每个个体在每一代中的移动次数为 (N - 1) / 2,而在粒子群算法中,每个粒子在每一代中移动一次,因此标准FA的时间复杂度是PSO的N倍。同时,个体的多次移动,会导致结果震荡,收敛速度下降。

(1)标准FA

import numpy as np
import matplotlib.pyplot as plt
import copy
import time

class FA:
    def __init__(self, D, N, Beta0, gama, alpha, T, bound):
        self.D = D         #问题维数
        self.N = N         #群体大小
        self.Beta0 = Beta0 #最大吸引度
        self.gama = gama   #光吸收系数
        self.alpha = alpha #步长因子
        self.T = T
        self.X = (bound[1] - bound[0]) * np.random.random([N, D]) + bound[0]
        self.X_origin = copy.deepcopy(self.X)
        self.FitnessValue = np.zeros(N)
        for n in range(N):
            self.FitnessValue[n] = self.FitnessFunction(self.X[n, :])

    def DistanceBetweenIJ(self, i, j):
        return np.linalg.norm(self.X[i,:] - self.X[j,:])

    def BetaIJ(self, i, j):  # AttractionBetweenIJ
        return self.Beta0 * \
               np.math.exp(-self.gama * (self.DistanceBetweenIJ(i,j) ** 2))

    def update(self,i,j):
        self.X[i,:] = self.X[i,:] + \
                      self.BetaIJ(i,j) * (self.X[j,:] - self.X[i,:]) + \
                      self.alpha * (np.random.rand(self.D) - 0.5)

    def FitnessFunction(self, x_):
        return np.linalg.norm(x_) ** 2

    def FindNewBest(self, i):
        FFi = self.FitnessFunction(self.X[i,:])
        x_ = self.X[i, :] + self.alpha * (np.random.rand(self.D) - 0.5)
        ffi = self.FitnessFunction(x_)
        if ffi < FFi:
            self.X[i,:] = x_
            self.FitnessValue[i] = ffi

    def iterate(self):
        t = 0
        while t < self.T:
            for i in range(self.N):
                tag = 0
                FFi = self.FitnessValue[i]
                for j in range(self.N):
                    FFj = self.FitnessValue[j]
                    if FFj < FFi:
                        tag = 1
                        self.update(i, j)
                        self.FitnessValue[i] = self.FitnessFunction(self.X[i,:])
                        FFi = self.FitnessValue[i]
                if tag == 0:
                    self.FindNewBest(i)
            t += 1

    def find_min(self):
        v = np.min(self.FitnessValue)
        n = np.argmin(self.FitnessValue)
        return v, self.X[n,:]

if __name__ == '__main__':
    t = np.zeros(10)
    value = np.zeros(10)
    for i in range(10):
        fa = FA(10, 40, 1, 0.000001, 0.97, 100, [-100, 100])
        time_start = time.time()
        fa.iterate()
        time_end = time.time()
        t[i] = time_end - time_start
        value[i], n = fa.find_min()
    print("平均值:", np.average(value))
    print("最优值:", np.min(value))
    print("最差值:", np.max(value))
    print("平均时间:", np.average(t))

 

(2)拓扑结构为环形的FA

    def iterate(self):
        t = 0
        while t < self.T:
            for i in range(self.N):
                tag = 0
                FFi = self.FitnessValue[i]
                list = [(i-2)%self.N, (i-1)%self.N, (i+1)%self.N, (i+2)%self.N]
                for j in list:
                    FFj = self.FitnessValue[j]
                    if FFj < FFi:
                        tag = 1
                        self.update(i, j)
                        self.FitnessValue[i] = self.FitnessFunction(self.X[i,:])
                        FFi = self.FitnessValue[i]
                if tag == 0:
                    self.FindNewBest(i)
            t += 1

(3)随机更新

    def iterate(self):
        t = 0
        while t < self.T:
            for i in range(self.N):
                j = np.random.randint(0,self.N)
                FFi = self.FitnessValue[i]
                FFj = self.FitnessValue[j]
                if FFj < FFi:
                    self.update(i, j)
                    self.FitnessValue[i] = self.FitnessFunction(self.X[i,:])
                else:
                    self.FindNewBest(i)
            t += 1

# 这里需要注意,虽然网上都是说np.random.randint(a,b)是生成[a,b]之间的整数,但实验生成的整数中不包括整数b。

可以看到,从标准FA到环形拓扑结构,再到随机更新,时间复杂度从O(N^{2})变为了O(4N),再到O(N)。同时,我们也会发现,结果也逐渐震荡。

 

参考文献:

[1]王沈娟,高晓智.萤火虫算法研究综述[J].微型机与应用,2015,34(08):8-11.

[2] 魏伟一,文雅宏.一种精英反向学习的萤火虫优化算法[J]. 智能系统学报,2017,12(5):710-716. 

https://www.jianshu.com/p/fc84f3febff7

  • 9
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值