单目标 - - - - PSO(粒子群算法)
PSO也写了一个多月了吧,记得是今年3月底完成了
差不多是破釜沉舟式写出来的,当时写出来那个激动哇。。
因为就花一天,而且很简单,更主要的是,写过了JADE,这个写起来就思路清晰很多了。
我觉得这个问题是比较有意思的一个问题,它是模拟鸟群捕食行为的一种算法:
设想这样一个场景:一群鸟在随机搜索食物。在这个区域里只有一块食物。所有的鸟都不知道食物在那里。但是他们知道当前的位置离食物还有多远。那么找到食物的最优策略是什么呢。最简单有效的就是搜寻目前离食物最近的鸟的周围区域。
但是这个问题又继而演化成了一个物理问题了(这里得打个问号了,是我自己这么认为的)
PSO最主要的是有一个速度公式和一个位移公式,如下:
v[] = w * v[] + c1 * rand() * (pbest[] - present[]) + c2 * rand() * (gbest[] - present[])
present[] = persent[] + v[]
这里面的3个参数w,c1,c2是非常之重要的,w是惯性权重,如果它太大,相当于运动的惯性系数太大,会突然间超过目标(停不下来。。。),如果太小,那么飞行到目标解又得花很长的时间。更奇葩的应该是c1,c2的选取吧,等下看我程序里给的值吧(其实这里,标准算法的值是w=1.0,c1=c2=2.0的)
先看下PSO的基本流程吧
再贴一下百度上找的伪代码:
clear all; clc; format long; %------给定初始化条件---------------------------------------------- c1=1.4962; %学习因子1 c2=1.4962; %学习因子2 w=0.7298; %惯性权重 MaxDT=1000; %最大迭代次数 D=10; %搜索空间维数(未知数个数) N=40; %初始化群体个体数目 eps=10^(-6); %设置精度(在已知最小值时候用) %------初始化种群的个体(可以在这里限定位置和速度的范围)------------ for i=1:N for j=1:D x(i,j)=randn; %随机初始化位置 v(i,j)=randn; %随机初始化速度 end end %------先计算各个粒子的适应度,并初始化Pi和Pg---------------------- for i=1:N p(i)=f(x(i,:),D); y(i,:)=x(i,:); end pg=x(1,:); %Pg为全局最优 for i=2:N if f(x(i,:),D)<f(pg,D) pg=x(i,:); end end %------进入主要循环,按照公式依次迭代,直到满足精度要求------------ for t=1:MaxDT for i=1:N v(i,:)=w*v(i,:)+c1*rand*(y(i,:)-x(i,:))+c2*rand*(pg-x(i,:)); x(i,:)=x(i,:)+v(i,:); if f(x(i,:),D)<p(i) p(i)=f(x(i,:),D); y(i,:)=x(i,:); end if p(i)<f(pg,D) pg=y(i,:); end end Pbest(t)=f(pg,D); end %------最后给出计算结果 disp('*************************************************************') disp('函数的全局最优位置为:') Solution=pg' disp('最后得到的优化极值为:') Result=f(pg,D) disp('*************************************************************') %------算法结束---DreamSun GL & HF-----------------------------------
最后再贴下我自己写的代码吧(测试函数依旧用的JADE里的第一个,精度也非常精确了~~)
代码风格依旧很挫。。。。
#include<stdio.h> #include<time.h> #include<stdlib.h> #include<iostream> //#include<random> #include<cmath> #include<malloc.h> using namespace std; #define URAND rand()/(RAND_MAX+1.0) const int P_num=100; const double PI=acos(-1.0); const int G=1500; const double w=0.7162; //用0.72//// 崔文明用的0.7162,因此我也改用了,就相当准确了,不过标准的是0.729 //可以考虑线性变化的w的取值... //w=0.9-t/T*0.5,不过测试之后,效果更差了 const double c1=1.49445; const double c2=1.49445; const int D=30; int times; struct individual { double p[D+10]; double v[D+10]; double fitness; double pbest[D+10]; double val; } gbest,P[P_num+10]; double rand_low_high(double low,double high) { return (high-low)*URAND+low; } double calc_val(individual P) { double val=0; for(int i=1;i<=D;i++) val+=P.p[i]*P.p[i]; return val; } void calc_P_val() { for(int i=1; i<=P_num; i++) { P[i].val=calc_val(P[i]); } } void init_P()//初始化 { srand((unsigned)time(NULL)); for(int i=1; i<=P_num; i++) { for(int j=1; j<=D; j++) { P[i].p[j]=rand_low_high(-100,100); P[i].v[j]=rand_low_high(-100,100); } } calc_P_val(); //找出第一代里的pbest和gbest for(int i=1;i<=P_num;i++) { for(int j=1;j<=D;j++) P[i].pbest[j]=P[i].p[j]; P[i].fitness=P[i].val; } gbest=P[1]; //for(int i=2;i<=P_num;i++) //if(P[i].fitness>gbest.fitness) //gbest=P[i]; } int main() { srand((unsigned)time(NULL)); init_P(); // double w=0.7; for(times=1; times<=G; times++)//其实更新应该是可以从times=2开始的 //for(times=2; times<=G; times++) { for(int j=1;j<=P_num;j++) { for(int k=1;k<=D;k++) { P[j].v[k]=w*P[j].v[k]+c1*URAND*(P[j].pbest[k]-P[j].p[k])+ c2*URAND*(gbest.p[k]-P[j].p[k]); if(P[j].v[k]>100)P[j].v[k]=100.0; // printf("%f\n",P[j].v[k]); if(P[j].v[k]<-100)P[j].v[k]=-100.0; P[j].p[k]+=P[j].v[k]; if(P[j].p[k]>100)P[j].p[k]=100; // printf("%f\n",P[j].p[k]); if(P[j].p[k]<-100)P[j].p[k]=-100; } P[j].val=calc_val(P[j]); if(P[j].val<P[j].fitness) { for(int k=1;k<=D;k++) P[j].pbest[k]=P[j].p[k]; P[j].fitness=P[j].val; } //收敛速度更快???? if(P[j].fitness<gbest.fitness)gbest=P[j]; } // w=0.7-times/G*0.5; //标准算法是在每代开始更新gbest的 //for(int j=1;j<=P_num;j++)if(P[j].fitness<gbest.fitness)gbest=P[j]; } gbest.val=calc_val(gbest); cout<<"the best value: "<<gbest.val<<endl<<endl; printf("time: %.6f\n\n\n\n",(double)clock()/CLOCKS_PER_SEC); system("pause"); return 0; }
posted on 2012-04-28 10:48 louzhang_swk 阅读(3180) 评论(1) 编辑 收藏 举报