粒子群算法PSO


算法描述

PSO中,每个优化问题的解都是搜索空间中一个“粒子”。所有的粒子都有一个由被优化的函数决定的适应值(fitness value),每个粒子还有一个速度决定他们移动的方向和距离。然后粒子们就追随当前的最优粒子在解空间中搜索。PSO 初始化为一群随机粒子(随机解)。然后通过迭代找到最优解。在每一次迭代中,粒子通过跟踪两个"极值"来更新自己。第一个就是粒子本身所找到的最优解,这个解叫做个体极值pBest。另一个极值是整个种群目前找到的最优解,这个极值是全局极值gBest。另外也可以不用整个种群而只是用其中一部分作为粒子的邻居,那么在所有邻居中的极值就是局部极值。

算法参数解释

速度和位置公式

粒子只有两个重要属性:位置和速度,速度和物理中的速度含义有所区别,这里可以理解为位置的变化量的多少快慢。粒子通过跟踪两个“极值”(pbest,gbest)来更新自己。在找到这两个最优值后,粒子通过下面的公式来更新自己的速度和位置:

v_i=\omega \times v_i+c_1 \times rand() \times \left( pbest_i-x_i \right)+c_2 \times rand() \times \left( gbest_i-x_i \right)
\tag{1}
x_i=x_i+v_i
\tag{2}

对于公式(1),第一部分称为 记忆项 ,表示上一次速度大小和方向的影响。第二部分称为 自身认知项 ,是粒子自己找到的最优解的影响。第三部分称为 群体认知项 ,是粒子群找到的最优解的影响。公式(2)就是通过公式(1)调整粒子的位置。

系数解释

叫做惯性因子,值为非负。其值较大,全局寻优能力强,局部寻优能力弱。可采用线性递减权值的方法设置动态,其公式为:。其中:初始惯性权值,:迭代至最大迭代次数时的惯性权值,最大迭代次数,当前迭代次数。典型的权值设置为:

为介于0到1之间的随机数。

为学习因子,通常取

算法流程

  1. 初始化一群微粒(群体规模为N),包括随机位置和速度;

  2. 评价每个微粒的适应度;

  3. 对每个微粒,将其适应值与其经过的最好位置pbest作比较,如果较好,则将其作为当前的最好位置pbest;

  4. 对每个微粒,将其适应值与其经过的最好位置gbest作比较,如果较好,则将其作为当前的最好位置gbest;

  5. 根据公式调整微粒速度和位置;

  6. 未达到结束条件则转第2步。 迭代终止条件根据具体问题一般选为最大迭代次数Gk或微粒群迄今为止搜索到的最优位置满足预定最小适应阈值

pso

求解函数的最大值的JAVA版本代码如下:

public class App {
    int n=4;  //设定粒子数 
    double x[]; //横坐标矩阵,粒子的位置
    double y[]; //目标函数值,可以说是适应度
    double v[]; //粒子移动速度
    double c1=2; 
    double c2=2;
    double omega=0.4;
    double pbest_x[]; 
    double pbest_y[];
    double gbest_x; 
    double gbest_y;
    double vmax=0.1; //设定最大速度,也就是最多只移动0.1个单位
	
	//计算目标函数值
    public double targetFunction(double arg){
        return -arg*(arg-2);
    }

    //计算粒子适应度函数
    public void fitnessFunction(){
        for(int i=0;i<n;i++){
            y[i]=-x[i]*(x[i]-2);
        }
    }

   //初始化
    public void init(){
        x=new double[n];
        y=new double[n];
        v=new double[n];
        pbest_x=new double[n];
        pbest_y=new double[n];
        //初始化粒子位置和速度
        for(int i=0;i<n;i++){
        	//取大一点可以感受收敛的广度
            x[i]=(Math.random()-0.5)*5;
            //取大一点可以感受收敛的速度
            v[i]=Math.random()*0.1;
        }
        //初始化初始迭代个体最优和群体最优
        for(int i=0;i<n;i++){
            pbest_x[i]=x[i];
            pbest_y[i]=targetFunction(x[i]);
            if(targetFunction(x[i])>gbest_y){
                gbest_x=x[i];
                gbest_y=targetFunction(gbest_x);
            }
        }
        System.out.println("PSO start:"+gbest_y);
        System.out.println("\n");
    }

	//用于判断大小
    public double getMAX(double a,double b){
        return a>b?a:b;
    }
    
	//粒子群算法
    public void PSO(int max){
    	//对于每一次迭代
        for(int i=0;i<max;i++){
        	//对于每一个粒子
            for(int j=0;j<n;j++){
                v[j]=omega*v[j]+c1*Math.random()*(pbest_x[j]-x[j])+c2*Math.random()*(gbest_x-x[j]);
                //速度越界处理
                if(v[j]>vmax){
                    v[j]=vmax;
                }
                //位置移动
                x[j]+=v[j];
                //位置越界处理
                if(x[j]<0) x[j]=0;
                if(x[j]>2) x[j]=2;
            }
            fitnessFunction();
            //更新个体最优和群体最优
            for(int j=0;j<n;j++){
                pbest_y[j]=getMAX(targetFunction(x[j]), pbest_y[j]);
                if(pbest_y[j]>gbest_y){
                    gbest_y=pbest_y[j];
                    gbest_x=x[j];
                }
                System.out.println("particle"+j+": ("+x[j]+","+targetFunction(x[j])+")"+" v = "+v[j]);
            }
            System.out.println("this is "+(i+1)+" epoch, gbset is ("+gbest_x+","+gbest_y+")");
            System.out.println("\n");
        }
    }
    public static void main(String[] args) throws Exception {
        App test=new App();
        test.init();
        test.PSO(20);
    }
}

本文章使用limfx的vscode插件快速发布