C语言实现粒子群算法(PSO)一

来源:互联网 发布:东华软件应收账款 编辑:程序博客网 时间:2024/06/05 04:51

        最近在温习C语言,看的书是《C primer Plus》,忽然想起来以前在参加数学建模的时候,用过的一些智能算法,比如遗传算法、粒子群算法、蚁群算法等等。当时是使用MATLAB来实现的,而且有些MATLAB自带了工具箱,当时有些只是利用工具箱求最优解问题,没有自己动手亲自去实现一遍,现在都忘的差不多了。我觉得那样层次实在是很浅没有真正理解算法的核心思想。本着“纸上得来终觉浅,绝知此事要躬行”的态度,我决定现在重新复习一遍算法,然后手工用C语言重新实现一遍。说做就做,我第一个实现的算法是相对来说比较简单的粒子群算法(与遗传算法等相比,至少我自己觉得实现要简单一些)。

      首先简单介绍一下启发式算法和智能算法。粒子群算法、遗传算法等都是从传统的搜索算法演变而来的启发式算法。启发式算法(heuristic algorithm)是相对于最优化算法提出的。一个问题的最优算法求得该问题每个实例的最优解。启发式算法可以这样定义:一个基于直观或经验构造的算法,在可接受的花费(指计算时间和空间)下给出待解决组合优化问题每一个实例的一个可行解,该可行解与最优解的偏离程度一般不能被预计,但是通常情况下启发式算法可以给出接近最优解的不错的解,但是无法保证每次它都可以得到很好的近似解。启发式算法中有一类被称之为智能算法,所谓"智能"二字,指的是这种算法是通过模仿大自然中的某种生物或者模拟某种现象而抽象得到的算法,比如遗传算法就是模拟自然界生物自然选择,优胜劣汰,适者生存而得到的进化算法,粒子群是源于对于鸟类捕食行为的研究,而模拟退火算法则是根据物理学中固体物质的退火过程抽象得到的优化算法。智能算法兴起于上个世纪80年代左右,之后就一直发展迅速,除了传统的智能算法之外,近几年又涌现出了一些新的算法比如鱼群算法、蜂群算法等。

      言归正传,下面来介绍今天的主角:粒子群算法。粒子群算法的基本原理如下(参考《MATLAB智能算法30个案例分析》):

      假设在一个D维的搜索空间中,由n个粒子组成的种群X=(X1,X2,..,Xn),其中第i个粒子表示为一个D维的向量Xi=(xi1,xi2,xiD),代表第i个粒子在D维搜索空间中的位置,亦代表问题的一个潜在解。根据目标函数即可以计算出每个粒子位置Xi对应的适应度值。第i个粒子的速度为Vi = (Vi1,Vi2,...,ViD),其个体极值为Pi=(Pi1,Pi2,...,PiD),种群的群体极值为Pg=(Pg1,Pg2,...,PgD)。在每次迭代的过程中,粒子通过个体极值和群体极值更新自身的速度和位置,即:

Vid(k+1)=w*Vid(k)+c1*r1*(Pid(k)-Xid(k))+c2*r2*(Pgd(k)-Xid(k))
Xid(k+1) = Xid(k) + Vid(k+1)
其中w为惯性权重,如果不考虑可以默认为1,后面还会再详细讨论w对于PSO的影响。d=1,2,..,D;i=1,2,...,n;k为当前迭代次数;Vid为粒子的速度;c1和c2是非负的常数,称为加速度因子;r1和r2是分布于[0,1]之间的随机数。为了防止粒子的盲目搜索,一般建议将其位置和速度限制在一定的区间内。

      下面是我用C语言实现的求一个二元函数最大值的粒子群算法:

/* * 使用C语言实现粒子群算法(PSO) * 参考自《MATLAB智能算法30个案例分析》 * update: 16/12/3* 本例的寻优非线性函数为 * f(x,y) = sin(sqrt(x^2+y^2))/(sqrt(x^2+y^2)) + exp((cos(2*PI*x)+cos(2*PI*y))/2) - 2.71289 * 该函数有很多局部极大值点,而极限位置为(0,0),在(0,0)附近取得极大值 */#include<stdio.h>#include<stdlib.h>#include<math.h>#include<time.h>#define c1 1.49445 //加速度因子一般是根据大量实验所得#define c2 1.49445#define maxgen 300  // 迭代次数#define sizepop 20 // 种群规模#define popmax 2 // 个体最大取值#define popmin -2 // 个体最小取值#define Vmax 0.5 // 速度最大值#define Vmin -0.5 //速度最小值#define dim 2 // 粒子的维数#define PI 3.1415926 //圆周率double pop[sizepop][dim]; // 定义种群数组double V[sizepop][dim]; // 定义种群速度数组double fitness[sizepop]; // 定义种群的适应度数组double result[maxgen];  //定义存放每次迭代种群最优值的数组double pbest[sizepop][dim];  // 个体极值的位置double gbest[dim]; //群体极值的位置double fitnesspbest[sizepop]; //个体极值适应度的值double fitnessgbest; // 群体极值适应度值double genbest[maxgen][dim]; //每一代最优值取值粒子//适应度函数double func(double * arr){double x = *arr; //x 的值double y = *(arr+1); //y的值double fitness = sin(sqrt(x*x+y*y))/(sqrt(x*x+y*y)) + exp((cos(2*PI*x)+cos(2*PI*y))/2) - 2.71289;return fitness;}// 种群初始化void pop_init(void){for(int i=0;i<sizepop;i++){for(int j=0;j<dim;j++){pop[i][j] = (((double)rand())/RAND_MAX-0.5)*4; //-2到2之间的随机数V[i][j] = ((double)rand())/RAND_MAX-0.5; //-0.5到0.5之间}fitness[i] = func(pop[i]); //计算适应度函数值}}// max()函数定义double * max(double * fit,int size){int index = 0; // 初始化序号double max = *fit; // 初始化最大值为数组第一个元素    static double best_fit_index[2];for(int i=1;i<size;i++){if(*(fit+i) > max)max = *(fit+i);index = i;}best_fit_index[0] = index;best_fit_index[1] = max;return best_fit_index;}// 迭代寻优void PSO_func(void){pop_init();double * best_fit_index; // 用于存放群体极值和其位置(序号)best_fit_index = max(fitness,sizepop); //求群体极值int index = (int)(*best_fit_index);// 群体极值位置for(int i=0;i<dim;i++){gbest[i] = pop[index][i];}// 个体极值位置for(int i=0;i<sizepop;i++){for(int j=0;j<dim;j++){pbest[i][j] = pop[i][j];}}// 个体极值适应度值for(int i=0;i<sizepop;i++){fitnesspbest[i] = fitness[i];}//群体极值适应度值double bestfitness = *(best_fit_index+1);fitnessgbest = bestfitness;//迭代寻优for(int i=0;i<maxgen;i++){for(int j=0;j<sizepop;j++){//速度更新及粒子更新for(int k=0;k<dim;k++){// 速度更新double rand1 = (double)rand()/RAND_MAX; //0到1之间的随机数double rand2 = (double)rand()/RAND_MAX;V[j][k] = V[j][k] + c1*rand1*(pbest[j][k]-pop[j][k]) + c2*rand2*(gbest[k]-pop[j][k]);if(V[j][k] > Vmax)V[j][k] = Vmax;if(V[j][k] < Vmin)V[j][k] = Vmin;// 粒子更新pop[j][k] = pop[j][k] + V[j][k];if(pop[j][k] > popmax)pop[j][k] = popmax;if(pop[j][k] < popmin)pop[j][k] = popmin;}fitness[j] = func(pop[j]); //新粒子的适应度值}for(int j=0;j<sizepop;j++){// 个体极值更新if(fitness[j] > fitnesspbest[j]){for(int k=0;k<dim;k++){pbest[j][k] = pop[j][k];}fitnesspbest[j] = fitness[j];}// 群体极值更新if(fitness[j] > fitnessgbest){for(int k=0;k<dim;k++)gbest[k] = pop[j][k];fitnessgbest = fitness[j];}}for(int k=0;k<dim;k++){genbest[i][k] = gbest[k]; // 每一代最优值取值粒子位置记录}result[i] = fitnessgbest; // 每代的最优值记录到数组}}// 主函数int main(void){clock_t start,finish; //程序开始和结束时间start = clock(); //开始计时srand((unsigned)time(NULL)); // 初始化随机数种子PSO_func();double * best_arr;best_arr = max(result,maxgen);int best_gen_number = *best_arr; // 最优值所处的代数double best = *(best_arr+1); //最优值printf("迭代了%d次,在第%d次取到最优值,最优值为:%lf.\n",maxgen,best_gen_number+1,best);printf("取到最优值的位置为(%lf,%lf).\n",genbest[best_gen_number][0],genbest[best_gen_number][1]);finish = clock(); //结束时间double duration = (double)(finish - start)/CLOCKS_PER_SEC; // 程序运行时间printf("程序运行耗时:%lf\n",duration);return 0;}

我运行C采用的是Ubuntu16 下的gcc编译器,运行结果截图如下:


多次运行结果差不多,基本每次都可以很接近最优解。而且发现C语言运行时间要远快于MATLAB实现(我记得MATLAB要用好几秒,这里就不贴MATLAB代码进行运行时间对比了),只需要耗时0.004秒左右。这里只讨论了基本的粒子群算法,后面一篇我还会对于粒子群的参数w进行详细的讨论,讨论不同的w参数的取法对于粒子群寻优能力的影响。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 脸上的疤变黑了怎么办 唱吧不能凳入怎么办 唱吧密码忘了怎么办 yy违规b类z怎么办 奇云2中控台褪色怎么办 uv打印错一个字怎么办 多肉砍头后的桩怎么办 哥哥太爱我怎么办电影 吃了减肥药怀孕怎么办 win10玩不了qq堂怎么办 电脑只有c盘了怎么办 美拍直播没人看怎么办 洛神花孕妇喝了怎么办 黑枸杞泡水褐色怎么办 红薯吃多了胃胀怎么办 在赌场掉了筹码怎么办? 到缅甸被绑架了怎么办 在淘宝不给退货怎么办 鞋上魔术贴坏了怎么办 手机支架不粘了怎么办 赌博把房子输了怎么办 当发现老公有外遇时怎么办 led灯带中间不亮怎么办 飘窗的天花板凸怎么办 一受委屈就爱哭怎么办 6岁儿童叛逆期怎么办 孩子高一了厌学怎么办 除上有肥胖纹怎么办 6岁不爱写作业怎么办 初中孩子不爱写作业怎么办 孩子上课走神写作业慢怎么办 孩子作业写得慢怎么办 4岁宝宝不写作业怎么办 小孩作业写得慢怎么办 3岁宝宝不写作业怎么办 小孩不写作业怎么办呀 作业没写完的人怎么办? 孩子不写作业家长该怎么办 做作业做得慢怎么办 高一作业写得慢怎么办 孩子做作业不认真怎么办