一、粒子群算法的概念
粒子群优化算法(PSO:Particle swarm optimization) 是一种进化计算技术(evolutionary computation)。源于对鸟群捕食的行为研究。粒子群优化算法的基本思想:是通过群体中个体之间的协作和信息共享来寻找最优解.
PSO的优势:在于简单容易实现并且没有许多参数的调节。目前已被广泛应用于函数优化、神经网络训练、模糊系统控制以及其他遗传算法的应用领域。
二、粒子群算法分析
1、基本思想
粒子群算法通过设计一种无质量的粒子来模拟鸟群中的鸟,粒子仅具有两个属性:速度和位置,速度代表移动的快慢,位置代表移动的方向。每个粒子在搜索空间中单独的搜寻最优解,并将其记为当前个体极值,并将个体极值与整个粒子群里的其他粒子共享,找到最优的那个个体极值作为整个粒子群的当前全局最优解,粒子群中的所有粒子根据自己找到的当前个体极值和整个粒子群共享的当前全局最优解来调整自己的速度和位置。下面的动图很形象地展示了PSO算法的过程:
2、更新规则
PSO初始化为一群随机粒子(随机解)。然后通过迭代找到最优解。在每一次的迭代中,粒子通过跟踪两个“极值”(pbest,gbest)来更新自己。在找到这两个最优值后,粒子通过下面的公式来更新自己的速度和位置。
公式(1)的第一部分称为【记忆项】,表示上次速度大小和方向的影响;公式(1)的第二部分称为【自身认知项】,是从当前点指向粒子自身最好点的一个矢量,表示粒子的动作来源于自己经验的部分;公式(1)的第三部分称为【群体认知项】,是一个从当前点指向种群最好点的矢量,反映了粒子间的协同合作和知识共享。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。以上面两个公式为基础,形成了PSO的标准形式。
公式(2)和 公式(3)被视为标准PSO算法。
3、PSO算法的流程和伪代码
4、PSO算法举例
5、PSO算法的代码
参考代码1:#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <ctime>
#define rand_01 ((float)rand() / (float)RAND_MAX)
const int numofdims = 30;
const int numofparticles = 50;
using namespace std;
//typedef void (*FitnessFunc)(float X[numofparticles][numofdims], float fitnesses[numofparticles]);
void fitnessfunc(float X[numofparticles][numofdims], float fitnesses[numofparticles])
{
memset(fitnesses, 0, sizeof (float) * numofparticles);
for(int i = 0; i < numofparticles; i++)
{
for(int j = 0; j < numofdims; j++)
{
fitnesses[i] += X[i][j] * X[i][j]; //(pow(X[i][j], 2));
}
}
}
void rosenBroekFunc(float X[numofparticles][numofdims], float fitnesses[numofparticles])
{
float x1, x2, t1, t2;
memset(fitnesses, 0, sizeof (float) * numofparticles);
for(int i = 0; i < numofparticles; i++)
for(int j = 0; j < numofdims - 1; j++)
{
x1 = X[i][j];
x2 = X[i][j+1];
t1 = (x2 - x1 * x1);
t1 *= t1;
t1 *= 100;
t2 = x1 - 1;
t2 *= t2;
fitnesses[i] = t1 + t2;
}
}
float mean(float inputval[], int vallength)
{
float addvalue = 0;
for(int i = 0; i < vallength; i++)
{
addvalue += inputval[i];
}
return addvalue / vallength;
}
void PSO(int numofiterations, float c1, float c2,
float Xmin[numofdims], float Xmax[numofdims], float initialpop[numofparticles][numofdims],
float worsts[], float meanfits[], float bests[], float *gbestfit, float gbest[numofdims])
{
float V[numofparticles][numofdims] = {0};
float X[numofparticles][numofdims];
float Vmax[numofdims];
float Vmin[numofdims];
float pbests[numofparticles][numofdims];
float pbestfits[numofparticles];
float fitnesses[numofparticles];
float w;
float minfit;
int minfitidx;
memcpy(X, initialpop, sizeof(float) * numofparticles * numofdims);
fitnessfunc(X, fitnesses);
//rosenBroekFunc(X, fitnesses);
// fp(X, fitnesses);
minfit = *min_element(fitnesses, fitnesses + numofparticles);
minfitidx = min_element(fitnesses, fitnesses + numofparticles) - fitnesses;
*gbestfit = minfit;
memcpy(gbest, X[minfitidx], sizeof(float) * numofdims);
//设置速度极限
for(int i = 0; i < numofdims; i++)
{
Vmax[i] = 0.2 * (Xmax[i] - Xmin[i]);
Vmin[i] = -Vmax[i];
}
for(int t = 0; t < 1000; t++)
{
w = 0.9 - 0.7 * t / numofiterations;
//计算个体历史极小值
for(int i = 0; i < numofparticles; i++)
{
if(fitnesses[i] < pbestfits[i])
{
pbestfits[i] = fitnesses[i]; //pbestfits初始化尚未赋值
memcpy(pbests[i], X[i], sizeof(float) * numofdims);
}
}
for(int i = 0; i < numofparticles; i++)
{
for(int j = 0; j < numofdims; j++)
{
V[i][j] = min(max((w * V[i][j] + rand_01 * c1 * (pbests[i][j] - X[i][j])
+ rand_01 * c2 * (gbest[j] - X[i][j])), Vmin[j]), Vmax[j]);
X[i][j] = min(max((X[i][j] + V[i][j]), Xmin[j]), Xmax[j]);
}
}
fitnessfunc(X, fitnesses);
//rosenBroekFunc(X, fitnesses);
minfit = *min_element(fitnesses, fitnesses + numofparticles);
minfitidx = min_element(fitnesses, fitnesses + numofparticles) - fitnesses;
if(minfit < *gbestfit)
{
*gbestfit = minfit;
//cout << "It=" << t << "->" << minfit << endl;
memcpy(gbest, X[minfitidx], sizeof(float) * numofdims);
}
worsts[t] = *max_element(fitnesses, fitnesses + numofparticles);
bests[t] = *gbestfit;
meanfits[t] = mean(fitnesses, numofparticles);
}
}
int main()
{
time_t t;
srand((unsigned) time(&t));
float xmin[30], xmax[30];
float initpop[50][30];
float worsts[1000], bests[1000];
float meanfits[1000];
float gbestfit;
float gbest[30];
for(int i = 0; i < 30; i++)
{
xmax[i] = 100;
xmin[i] = -100;
}
for(int i = 0; i < 50; i++)
for(int j = 0; j < 30; j++)
{
initpop[i][j] = rand() % (100 + 100 + 1) - 100;
}
PSO(1000, 2, 2, xmin, xmax, initpop, worsts, meanfits, bests, &gbestfit, gbest);
cout<<"fitness: " << gbestfit << endl;
for(int i = 0; i < 30; i++)
cout << gbest[i] << ", ";
cout << endl;
return 0;
}
参考代码2:
#include"stdio.h"
#include"stdlib.h"
#include"time.h"
#include"math.h"
const int NUM=40;//粒子数
const int DIM=30;//维数
const double c1=1.8;//参数
const double c2=1.8;//参数
double xmin=-100.0;//位置下限
double xmax=100.0;//位置上限
double gbestx[DIM];//全局最优位置
double gbestf;//全局最优适应度
struct particle {//定义一个粒子
double x[DIM];//当前位置矢量
double bestx[DIM];//历史最优位置
double f;//当前适应度
double bestf;//历史最优适应度
}swarm[NUM];//定义粒子群
#define randf ((rand()%10000+rand()%10000*10000)/100000000.0) //产生-1随机浮点数
double f1(double x[]) {//测试函数:超球函数
float z=0;
for(int i=0;i<DIM;i++)
z+=(x[i])*(x[i]);
return z;
}
int main() {
for(int i=0; i<DIM; i++)//初始化全局最优
gbestx[i]=randf*(xmax-xmin)+xmin;
gbestf=100000000000000.0;
for(int i=0; i<NUM; i++) {//初始化粒子群
particle* p1=&swarm[i];
for(int j=0; j<DIM; j++)
p1->x[j]=randf*(xmax-xmin)+xmin;
p1->f=f1(p1->x);
p1->bestf=100000000000000.0;
}
for(int t=0; t<5000; t++) {
for(int i=0; i<NUM; i++) {
particle* p1=&swarm[i];
for(int j=0; j<DIM; j++)//进化方程
p1->x[j]+=c1*randf*(p1->bestx[j]-p1->x[j])
+c2*randf*(gbestx[j]-p1->x[j]);
p1->f=f1(p1->x);
if(p1->f<p1->bestf) {//改变历史最优
for(int j=0;j<DIM;j++)
p1->bestx[j]=p1->x[j];
p1->bestf=p1->f;
}
if(p1->f<gbestf) {//改变全局最优
for(int j=0;j<DIM;j++)
gbestx[j]=p1->x[j];
for(int j=0; j<DIM; j++)//把当前全局最优的粒子随机放到另一位置
p1->x[j]=randf*(xmax-xmin)+xmin;
gbestf=p1->f;
}
}
}
printf("%g\n", gbestf);
}
参考代码3:
/*
* 使用C语言实现粒子群算法(PSO) 改进版本
* 参考自《MATLAB智能算法30个案例分析》
* update: 16/12/3
* 主要改进的方面体现在w的选择上面
* 本例的寻优非线性函数为
* 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 repeat 100 // 重复实验次数
#define sizepop 20 // 种群规模
#define popmax 2 // 个体最大取值
#define popmin -2 // 个体最小取值
#define Vmax 0.5 // 速度最大值
#define Vmin -0.5 //速度最小值
#define dim 2 // 粒子的维数
#define w_start 0.9
#define w_end 0.4
#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;
}
// 迭代寻优,传入的参数为一个整数,取值为1到5,分别代表5种不同的计算w的方法
void PSO_func(int n)
{
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;
double w;
double Tmax = (double)maxgen;
switch(n)
{
case 1:
w = 1;
case 2:
w = w_end + (w_start - w_end)*(Tmax-i)/Tmax;
case 3:
w = w_start -(w_start-w_end)*(i/Tmax)*(i/Tmax);
case 4:
w = w_start + (w_start-w_end)*(2*i/Tmax-(i/Tmax)*(i/Tmax));
case 5:
w = w_end*(pow((w_start/w_end),(1/(1+10*i/Tmax))));
default:
w = 1;
}
V[j][k] = w*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)); // 初始化随机数种子
for(int i=1;i<=5;i++)
{
int near_best = 0; // 接近最优解的次数
double best_sum = 0; // 重复最优值求和
double best = 0; // 重复实验得到的最优解
for(int j=0;j<repeat;j++)
{
PSO_func(i); // 第i种w参数取值
double * best_fit_index = max(result,maxgen);
double best_result = *(best_fit_index+1); //最优解
if(best_result > 0.95)
near_best++;
if(best_result>best)
best = best_result;
best_sum += best_result;
}
double average_best = best_sum/repeat; //重复实验平均最优值
printf("w参数的第%d种方法:\n",i);
printf("重复实验%d次,每次实验迭代%d次,接近最优解的实验次数为%d次,求得最优值为:%lf,平均最优值为:%lf\n",repeat,maxgen,near_best,best,average_best);
}
finish = clock(); //结束时间
double duration = (double)(finish - start)/CLOCKS_PER_SEC; // 程序运行时间
printf("程序运行耗时:%lf\n",duration);
return 0;
}
参考:
https://blog.csdn.net/myarrow/article/details/51507671
https://blog.csdn.net/google19890102/article/details/30044945
https://wenku.baidu.com/view/65c600b9294ac850ad02de80d4d8d15abe230048.html
https://blog.csdn.net/darin1997/article/details/80675933
https://blog.csdn.net/daaikuaichuan/article/details/81382794
https://blog.csdn.net/miscclp/article/details/38652571
https://blog.csdn.net/hcc199521/article/details/53445656
https://blog.csdn.net/hcc199521/article/details/53446459