单目标 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;
}

 

 

 

原文地址:https://www.cnblogs.com/louzhang/p/2474743.html