饥饿游戏搜索算法(HGS)(含java实现代码)

Hunger games search: Visions, conception, implementation, deep analysis, perspectives, and towards performance shifts

期刊:Expert Systems With Applications SCI1区

主体框架

    public HGS(){
        initialize();
        calculateFitness();
        sortTheFitness();
        calculateHungry();

        for (t = 0;t<T;t++){
            UpdateWeight();
            UpdateLocation();
            calculateFitness();
            sortTheFitness();
            calculateHungry();
            savePoints();
        }
    }

ps:经过多次的复现以后,我发现实现一个算法最快的方式就是先将算法分模块搞好,所以上来先贴一个框架图。

在这里插入图片描述

这篇论文主要分为四个模块,分别是初始化模块,适应度与饥饿值设置模块,权重更新模块,位置更新模块。

论文有意思的点:

在这篇文章里面的公式非常的多,但是在这里我只想着重介绍这篇论文的创新点:饥饿机制。

文章定义了一个叫饥饿值的东西,如下公式所示。我们发现当且仅当i适应度值最小的时候,饥饿值为0,别的情况饥饿值为上次的饥饿值加上H。也就是说,只要适应度高,那么就会越来越饥饥饿。后面我们再说这个饥饿度怎么用。值得注意的是:每一轮迭代都会更新一次hungry值

 hungry  ( i ) = { 0 ,  AllFitness  ( i ) = = B F  hungry  ( i ) + H ,  AllFitness  ( i ) ! = B F \text { hungry }(i)=\left\{\begin{array}{c}0, \text { AllFitness }(i)==B F \\\text { hungry }(i)+H, \text { AllFitness }(i) !=B F\end{array}\right.  hungry (i)={0, AllFitness (i)==BF hungry (i)+H, AllFitness (i)!=BF

其中 B F BF BF为最差的适应度,也就是最小的适应度值。 H H H的定义如下所示

T H = F ( i ) − B F W F − B F × r 6 × 2 × ( U B − L B ) H = { L H × ( 1 + r ) , T H < L H T H , T H ≥ L H \begin{aligned}&T H=\frac{F(i)-B F}{W F-B F} \times r_6 \times 2 \times(U B-L B)\\&H=\left\{\begin{array}{c}L H \times(1+r), T H<L H \\T H, T H \geq L H\end{array}\right.\end{aligned} TH=WFBFF(i)BF×r6×2×(UBLB)H={LH×(1+r),TH<LHTH,THLH

其中 F ( i ) F(i) F(i)为适应度值, W F WF WF(Worse Fitness)为最大的适应度值(至今为止), U B 和 L B UB和LB UBLB为问题空间的上下界。 L H LH LH(Limit Hungry)则为饥饿感的下限,r是一个随机值。

也就是说当适应度值 F ( i ) F(i) F(i)越小的时候, T H TH TH(Temp Hungry)会越小,当低于上限的时候,本轮增加的饥饿度 H H H,将会被设置为大于 T H TH TH的一个随机值。

我们从上面的三个公式只要知道一个关键结论就好了:

适应度越小,越不饥饿。

适应度越大,这轮增加的饥饿度越高。

那么这个饥饿度值该怎么用呢?

W 1 ( i ) → = {  hungry  ( i ) ⋅ N  SHungry  × r 4 , r 3 < l 1 , r 3 > l \overrightarrow{W_1(i)}=\left\{\begin{array}{c}\text { hungry }(i) \cdot \frac{N}{\text { SHungry }} \times r_4, r_3<l \\1, r_3>l\end{array}\right. W1(i) ={ hungry (i) SHungry N×r4,r3<l1r3>l

W 2 ( i ) → = ( 1 − exp ⁡ ( − ∣  hungry  ( i ) −  SHungry  ∣ ) ) × r 5 × 2 \overrightarrow{W_2(i)}=(1-\exp (-\mid \text { hungry }(i)-\text { SHungry } \mid)) \times r_5 \times 2 W2(i) =(1exp( hungry (i) SHungry ))×r5×2

论文构建了两个向量,分别是 W 1 ( i ) , W 2 ( i ) W_1(i),W_2(i) W1(i),W2(i),这两个向量负责对个体进行变异,这里最关键的点是 S H u n g r y SHungry SHungry,这是所有 h u n g r y hungry hungry的总和,我们可以发现,两个向量组的规律。

对于 W 1 ( i ) W_1(i) W1(i)而言,hungry越小,里面的值越小

对于 W 2 ( i ) W_2(i) W2(i)而言,hungry越小,里面的值越接近2也就是说里面的值越大。

X ( t + 1 ) → = {  Game  1 : X ( t ) → ⋅ ( 1 + randn ⁡ ( 1 ) ) , r 1 < l  Game  2 : W 1 → ⋅ X b → + R ⃗ ⋅ W 2 → ⋅ ∣ X b → − X ( t ) → ∣ , r 1 > l , r 2 > E  Game  3 : W 1 → ⋅ X b → − R ⃗ ⋅ W 2 → ⋅ ∣ X b → − X ( t ) → ∣ , r 1 > l , r 2 < E \overrightarrow{X(t+1)}=\left\{\begin{array}{c}\text { Game }_1: \overrightarrow{X(t)} \cdot(1+\operatorname{randn}(1)), r_1<l \\\text { Game }_2: \overrightarrow{W_1} \cdot \overrightarrow{X_b}+\vec{R} \cdot \overrightarrow{W_2} \cdot\left|\overrightarrow{X_b}-\overrightarrow{X(t)}\right|, r_1>l, r_2>E \\\text { Game }_3: \overrightarrow{W_1} \cdot \overrightarrow{X_b}-\vec{R} \cdot \overrightarrow{W_2} \cdot\left|\overrightarrow{X_b}-\overrightarrow{X(t)}\right|, r_1>l, r_2<E\end{array}\right. X(t+1) =  Game 1:X(t) (1+randn(1)),r1<l Game 2:W1 Xb +R W2 Xb X(t) ,r1>l,r2>E Game 3:W1 Xb R W2 Xb X(t) ,r1>l,r2<E

最后,每轮迭代的时候都根据上面的公式对位置进行变换,在文中,l被设置为0.08,在公式1中,其实就是一个高斯变异,烟花算法也用到这个。

公式二和三,本质上是一个DE,差分进化的两个公式都是没头脑的,就算正向学习和反向学习,很多论文也有这个。最后还有个E,这个E也是作者自己设定的一个阈值,可以参照野狗群算法,不过作者将这个搜索阈值自己自定义了:

E = sech ⁡ ( ∣ F ( i ) − B F ∣ ) E=\operatorname{sech}(|F(i)-B F|) E=sech(F(i)BF)

( sech ⁡ ( x ) = 2 e x + e − x ) \left(\operatorname{sech}(x)=\frac{2}{e^x+e^{-x}}\right) (sech(x)=ex+ex2)

sech就是双曲正割函数

在这里插入图片描述

x越大,y越小,也就是说,当前解的适应度值越小,E就会越接近1,公式3被调用的概率就会变高。当前的解适应度越大,E就会越接近0,公式2被调用的概率越大。

最后再补充一个

R ⃗ = 2 ×  shrink  ×  rand  −  shrink   shrink  = 2 × ( 1 − t T ) \begin{aligned}& \vec{R}=2 \times \text { shrink } \times \text { rand }- \text { shrink } \\& \text { shrink }=2 \times\left(1-\frac{t}{T}\right)\end{aligned} R =2× shrink × rand  shrink  shrink =2×(1Tt)

这个东西就是随着迭代次数,波动逐渐减少的向量,最后会收敛到0,值得注意的是R里面是有正有负的,意味着game2和game3是存在等效的情况。

实验的截图~
在这里插入图片描述
在这里插入图片描述

寻找sphere最小值。

实际代码

import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.function.Consumer;

/**
 * Hunger games search: Visions, conception, implementation, deep analysis, perspectives, and towards performance shifts
 */

public class HGS {
    int N = 30;//5 10 30 50 100
    Double D;
    Double L = 0.08;
    Double H;
    Double SHungry;

    List<Double> Xb;
    double BF = Double.MAX_VALUE;
    double WF = -Double.MAX_VALUE;

    double lb = 0;
    double ub = 1;
    int dimension = 30;
    int t;
    int T = 1000;
    List<Double> R = new ArrayList<>(dimension);
    ArrayList<Point> res = new ArrayList<>();
    double LH = 10000;
    public HGS(){
        initialize();
        calculateFitness();
        sortTheFitness();
        calculateHungry();

        for (t = 0;t<T;t++){
            UpdateWeight();
            UpdateLocation();
            calculateFitness();
            sortTheFitness();
            calculateHungry();
            savePoints();
        }
    }

    public static void main(String[] args) {
        HGS hgs = new HGS();
        ArrayList<Point> points = hgs.res;

        // 创建绘制折线图的窗口
        JFrame frame = new JFrame("折线图");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new LineChart(points));
        frame.setSize(800, 600);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    public void savePoints(){
        System.out.println("curt:"+t+",BF="+BF);
        res.add(new Point(t,(int)(BF*100000)));
    }
    List<Individual> individuals = new ArrayList<>();
    public void initialize(){
        IndividualFactory individualFactory = new IndividualFactory(dimension,lb,ub);
        individuals = individualFactory.getRandomIndividuals(N);
        t = 0;
    }
    public void calculateFitness(){
        for (Individual i:
             individuals) {
            i.UpDateFitness();
        }
    }
    public void sortTheFitness(){
        individuals.sort((a,b)->new Double(a.fitness).compareTo(b.fitness));//按照适应度排序

        WF = Math.max(WF,individuals.get(N-1).fitness);
        if(BF>individuals.get(0).fitness){
            BF = individuals.get(0).fitness;
            Xb = new ArrayList<>(individuals.get(0).position);//copy一份
        }
        BF = Math.min(BF,individuals.get(0).fitness);
    }
    public void calculateHungry(){
        for (Individual i:
             individuals) {
            if(i.fitness==BF){
                i.hungry = 0;
            }else {
                double r6 = Math.random();
                Double TH = (i.fitness-BF)/(WF-BF)*r6*2*(ub-lb);
                Double H;
                if(TH<LH){
                    H = LH*(1+Math.random());
                }else {
                    H = TH;
                }

                i.hungry = i.hungry+H;
            }
        }
    }
    public void UpdateWeight(){
        double SHungry = 0;
        for (Individual i:
             individuals) {
            SHungry+=i.hungry;
        }
        for (Individual i:
             individuals) {
            i.updateW(N,SHungry,L);
        }
    }
    public void UpdateLocation(){
        for (Individual i:
             individuals) {
            i.upDateLocation(L,t,T,Xb,BF);
        }
    }
}

class Individual{
    double hungry;

    double fitness;
    double lb;
    double ub;
    List<Double> position = new ArrayList<>();
    List<Double> w1;
    List<Double> w2;
    int dimension;

    public double getHungry() {
        return hungry;
    }

    public void setHungry(double hungry) {
        this.hungry = hungry;
    }

    public Individual(double lb, double ub, List<Double> position) {
        this.lb = lb;
        this.ub = ub;
        this.position = position;
        dimension = position.size();
        w1 = new ArrayList<>(dimension);
        w2 = new ArrayList<>(dimension);
        for (int i = 0; i < dimension; i++) {
            w1.add(0.0);
            w2.add(0.0);
        }
    }

    public void Game1(){
        //formula 2.1
        Random random = new Random();
        for (int i = 0; i < dimension; i++) {
            double originX = position.get(i);
            position.set(i,originX*(1+random.nextGaussian()));
        }
    }
    public void Game2(List<Double> R,List<Double> Xb){
        //formula 2.1
        for (int i = 0; i < dimension; i++) {
            position.set(i,w1.get(i)*Xb.get(i)+R.get(i)*w2.get(i)*Math.abs(Xb.get(i)-this.position.get(i)));
        }
    }
    public void Game3(List<Double> R,List<Double> Xb){
        //formula 2.1
        for (int i = 0; i < dimension; i++) {
            position.set(i,w1.get(i)*Xb.get(i)-R.get(i)*w2.get(i)*Math.abs(Xb.get(i)-this.position.get(i)));
        }
    }
    public void upDateLocation(double l,int t,int T,List<Double> Xb,double BF){
        double r1 = Math.random();
        double r2 = Math.random();
        if(r1<l){
            Game1();
        }else{
            List<Double> R = new ArrayList<>(dimension);
            for (int i = 0; i < dimension; i++) {
                R.add(0.0);
            }
            double shrink = 2.0*(1.0-t/T);
            for (int i = 0; i < dimension; i++) {
                R.set(i,2*shrink*Math.random()-shrink);
            }
            double E = sech(Math.abs(fitness-BF));
            if(r2>E){
                Game2(R,Xb);
            }else {
                Game3(R,Xb);
            }
        }
    }
    public static double sech(double x){
        return 2.0/(Math.exp(x)+Math.exp(-x));
    }
    public void updateW(int N,double SHungry,double l){
        for (int i = 0; i < dimension; i++) {
            //formula 2.6
            double r3 = Math.random();
            double r4 = Math.random();
            if (r3<l){
                w1.set(i,hungry*N/SHungry*r4);
            }else {
                w1.set(i,1.0);
            }
            double r5 = Math.random();
            //formula 2.6
            w2.set(i,(1-Math.exp(-Math.abs(hungry-SHungry)))*r5*2);
        }
    }
    public void UpDateFitness(){
        this.fitness = Sphere(this.position);
    }
    public static double Sphere(List<Double> x){
        double sum = 0;
        for (int i = 0; i < x.size(); i++) {
            sum += x.get(i)*x.get(i);
        }
        return sum;//修正函数
    }
}
class IndividualFactory{
    Random random = new Random();
    private int dimension;
    private double lb;
    private double ub;
    public IndividualFactory(int dimension,double lb,double ub){
        this.dimension = dimension;
        this.lb = lb;
        this.ub = ub;
    }
    public Individual getRandom(){
        List<Double> Position = new ArrayList<>(dimension);
        for (int i = 0; i < dimension; i++) {
            Position.add(lb+(ub-lb)*random.nextDouble());
        }
        Individual individual = new Individual(lb,ub,Position);
        individual.UpDateFitness();
        return individual;
    }
    public List<Individual> getRandomIndividuals(int N){
        List<Individual> individuals = new ArrayList<>(N);
        for (int i = 0; i < N; i++) {
            individuals.add(getRandom());
        }
        return individuals;
    }

}
class LineChart extends JPanel {

    private ArrayList<Point> points;

    public LineChart(ArrayList<Point> points) {
        this.points = points;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        int margin = 50; // 留出一些边距
        int width = getWidth() - 2 * margin;
        int height = getHeight() - 2 * margin;

        // 绘制坐标轴
        g2d.drawLine(margin, margin, margin, margin + height); // 垂直轴
        g2d.drawLine(margin, margin + height, margin + width, margin + height); // 水平轴

        // 计算最大和最小的x和y值
        int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE;
        int maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
        for (Point point : points) {
            if (point.x < minX) minX = point.x;
            if (point.x > maxX) maxX = point.x;
            if (point.y < minY) minY = point.y;
            if (point.y > maxY) maxY = point.y;
        }

        // 绘制折线
        g2d.setColor(Color.BLUE);
        for (int i = 0; i < points.size() - 1; i++) {
            int x1 = margin + (points.get(i).x - minX) * width / (maxX - minX);
            int y1 = margin + height - (points.get(i).y - minY) * height / (maxY - minY);
            int x2 = margin + (points.get(i + 1).x - minX) * width / (maxX - minX);
            int y2 = margin + height - (points.get(i + 1).y - minY) * height / (maxY - minY);
            g2d.drawLine(x1, y1, x2, y2);
        }
    }

}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值