1. 概念
粒子群优化算法(PSO:Particle swarm optimization) 是一种进化计算技术(evolutionary computation)。
源于对鸟群捕食的行为研究。粒子群优化算法的基本思想:是通过群体中个体之间的协作和信息共享来寻找最优解.
PSO的优势:在于简单容易实现并且没有许多参数的调节。目前已被广泛应用于函数优化、神经网络训练、模糊系统控制以及其他遗传算法的应用领域。
2. 算法
2.1 问题抽象
鸟被抽象为没有质量和体积的微粒(点),并延伸到N维空间,粒子i在N维空间的位置表示为矢量Xi=(x1,x2,…,xN),飞行速度表示为矢量Vi=(v1,v2,…,vN)。每个粒子都有一个由目标函数决定的适应值(fitness value),并且知道自己到目前为止发现的最好位置(pbest)和现在的位置Xi。这个可以看作是粒子自己的飞行经验。除此之外,每个粒子还知道到目前为止整个群体中所有粒子发现的最好位置(gbest)(gbest是pbest中的最好值),这个可以看作是粒子同伴的经验。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。
2.2 更新规则
PSO初始化为一群随机粒子(随机解)。然后通过迭代找到最优解。在每一次的迭代中,粒子通过跟踪两个“极值”(pbest,gbest)来更新自己。在找到这两个最优值后,粒子通过下面的公式来更新自己的速度和位置。
公式(1)的第一部分称为【记忆项】,表示上次速度大小和方向的影响;公式(1)的第二部分称为【自身认知项】,是从当前点指向粒子自身最好点的一个矢量,表示粒子的动作来源于自己经验的部分;公式(1)的第三部分称为【群体认知项】,是一个从当前点指向种群最好点的矢量,反映了粒子间的协同合作和知识共享。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。
以上面两个公式为基础,形成了PSO的标准形式。
公式(2)和 公式(3)被视为标准PSO算法。
3.算法 C++实现
/***
* 计算y=-x(x-1)的最大值
* 取值范围x--[-2,2]
* @author BreezeDust
*
*/
public class PSOTest {
int n=2; //粒子个数,这里为了方便演示,我们只取两个,观察其运动方向
double[] y;
double[] x;
double[] v;
double c1=2;
double c2=2;
double pbest[];
double gbest;
double vmax=0.1;
public void fitnessFunction(){//适应函数
for(int i=0;i<n;i++){
y[i]=-1*x[i]*(x[i]-2);
}
}
public void init(){ //初始化
x=new double[n];
v=new double[n];
y=new double[n];
pbest=new double[n];
/***
* 本来是应该随机产生的,为了方便演示,我这里手动随机落两个点,分别落在最大值两边
*/
x[0]=-0.5;
x[1]=2.6;
v[0]=0.01;
v[1]=0.02;
fitnessFunction();
//初始化当前个体极值,并找到群体极值
for(int i=0;i<n;i++){
pbest[i]=y[i];
if(y[i]>gbest) gbest=y[i];
}
System.out.println("start gbest:"+gbest);
}
public double getMAX(double a,double b){
return a>b?a:b;
}
//粒子群算法
public void PSO(int max){
for(int i=0;i<max;i++){
double w=0.4;
for(int j=0;j<n;j++){
//更新位置和速度
v[j]=w*v[j]+c1*Math.random()*(pbest[j]-x[j])+c2*Math.random()*(gbest-x[j]);
if(v[j]>vmax) v[j]=vmax;
x[j]+=v[j];
//越界判断
if(x[j]>2) x[j]=2;
if(x[j]<-2) x[j]=-2;
}
fitnessFunction();
//更新个体极值和群体极值
for(int j=0;j<n;j++){
pbest[j]=getMAX(y[j],pbest[j]);
if(pbest[j]>gbest) gbest=pbest[j];
System.out.println(x[j]+" "+v[j]);
}
System.out.println("======"+(i+1)+"======gbest:"+gbest);
}
}
public static void main(String[] args){
PSOTest ts=new PSOTest();
ts.init();
ts.PSO(100);
}
}
输出结果
start gbest:0.0
-0.4 0.1
0.0 -10.751668729351186
======1======gbest:0.0
-0.6822365786740794 -0.2822365786740793
0.0 -5.375834364675593
======2======gbest:0.0
-0.5822365786740794 0.1
0.0 -2.6879171823377965
======3======gbest:0.0
-0.48223657867407943 0.1
-1.3439585911688983 -1.3439585911688983
======4======gbest:0.0
-0.38223657867407945 0.1
-1.2439585911688982 0.1
======5======gbest:0.0
-0.47659030560462123 -0.09435372693054181
-1.143958591168898 0.1
======6======gbest:0.0
-0.37659030560462126 0.1
-1.043958591168898 0.1
======7======gbest:0.0
-0.2765903056046213 0.1
-0.943958591168898 0.1
======8======gbest:0.0
-0.27903394174424034 -0.0024436361396190653
-0.843958591168898 0.1
======9======gbest:0.0
-0.38899022876058803 -0.10995628701634769
-0.7439585911688981 0.1
======10======gbest:0.0
-0.35250959144436234 0.03648063731622572
-0.6439585911688981 0.1
======11======gbest:0.0
........
........
........
........
0.9999990975760489 -1.556071309835406E-6
======98======gbest:1.0
1.0000000029937202 4.411275849326098E-9
1.0000001827158205 1.085139771533034E-6
======99======gbest:1.0
0.9999999993730952 -3.6206249540206964E-9
1.0000001197322141 -6.298360633295484E-8
======100======gbest:1.0
结果分析
我们可以从打印的数据看出来,刚开始x[0]和x[1]分散在最大值两边,然后x[0]和x[1]逐渐聚集到1的周围,这里,我们已经收敛到x=1这个地方了,这正是我们要求的最大值,其最大值为1,下面是图解过程。
1.初始状态
2.第二次x[1]向左边移动了
3.最后,两点聚集在1上,上面多个圈是他们聚集的过程,可以看出来,聚集过程是个越来越密集的过程。
转载原文链接1:https://blog.csdn.net/qq_34504481/article/details/79763824