粒子群优化算法源于对一个简化鸟群的模拟。算法中的每个粒子可视为N维搜索空间中的一个搜索个体,粒子有两个属性:速度和位置。粒子的当前位置即为对应优化问题的一个候选解,粒子的飞行过程即为该个体的搜索过程。粒子的飞行速度可根据粒子历史最优位置和种群历史最优位置进行动态调整。飞行速度和位置的更新公式如下。
其中w为惯性系数,C1为个体经验系数,C2为社会经验系数。为每个粒子单独搜寻的最优解,即个体极值,为粒子群中最优的个体极值,即当前的全局最优解。算法通过不断迭代,更新速度和位置。最终得到满足终止条件的最优解。
我在实践过程中发现,粒子群很容易陷入局部最优。想要达到最优解,需要多次运行程序进行尝试,实际应用中可能非常麻烦。于是我联想遗传算法,为粒子群算法加入了变异,以跳出局部最优。伪代码代码如下。
b ← 取一个0到1之间的随机数
if b>0.98 //有0.02的几率发生变异
int x ← 0~(维度-1) 之间的随机数
for j ← 0 to n do //对所有个体
p[j].pos[x] ←随机数 //将所有粒子x维的坐标打乱
end
加入变异机制后,提高了算法的稳定性,对很多连续函数均可以通过一次搜索找到最优解,但问题在于对粒子群的参数和变异率要求过高,否则收敛很慢,如何调整到最佳值得继续研究。 下面的代码中没有加入变异机制。
#include<iostream>
#include<vector>
#include<time.h>
using namespace std;
const int SIZE = 10; //种群规模
const int DIMENSION = 2; //目标函数维数
const double W = 0.4; //惯性系数
const double C1 = 2; //个体认知常数
const double C2 = 2; //社会经验常数
const int ITER_NUM = 30; //进化30代
const vector<double> LOWER_BOUND(DIMENSION, -30); //每一个维度的位置下限
const vector<double> UPPER_BOUND(DIMENSION, 30); //每一个维度的位置上限
const vector<double> MIN_VELO(DIMENSION, -60); //每一个维度的速度下限
const vector<double> MAX_VELO(DIMENSION, 60); //每一个维度的速度上限
struct Single { //个体结构
vector<double>m_x; //n维坐标
vector<double>m_v; //速度
double m_fitness; //适应度
vector<double> m_pbest; //个体最优点
Single() { //构造函数
m_x = vector<double>(DIMENSION); //初始化坐标
m_v = vector<double>(DIMENSION); //初始化速度
m_pbest = m_x; //初始化最优点
m_fitness = 0; //初始化适应度
}
};
vector<double> gbest(DIMENSION); //全局最优点
vector<Single>population(SIZE); //种群容器
double RandReal(int left, int right); //得到一个随机实数
double RandInt(int left, int right); //得到一个随机整数
void Print(); //打印群体情况
void InitPop(); //初始化群体
double CalculateFitness(vector<double>x); //计算适应度
void FreshVelocity(int i); //更新个体速度
void FreshPosition(int i); //更新个体位置
int main() //主函数
{
srand((unsigned)time(NULL)); //随机数种子
InitPop(); //初始化群体
gbest = population[0].m_x; //初始化全局最优点
Print(); //打印群体情况
cout << endl;
for (int i = 0; i < ITER_NUM; i++){ //循环迭代,迭代次数为常量
for (int j = 0; j < SIZE; j++){ //对每一个个体进行操作
double mybestfit = CalculateFitness(population[j].m_pbest); //计算个体最优点的适应值
double globalfit = CalculateFitness(gbest); //计算全局最优点的适应值
if (population[j].m_fitness < mybestfit) //若个体的适应值优于个体最优点
population[j].m_pbest = population[j].m_x; //更新个体最优点
if (population[j].m_fitness < globalfit) //若个体的适应值优于全局最优点
gbest = population[j].m_x; //更新全局最优点
FreshVelocity(j); //更新个体的速度
FreshPosition(j); //更新个体的位置
}
Print(); //打印群体情况
cout << endl;
}
cin.get();
}
void Print(){ //函数:打印群体情况
for (auto var : population) //遍历每个个体
cout <<"coordinate:" << var.m_x[0] << "," << var.m_x[1] //打印个体位置
<<"velocity:"<<var.m_v[0] << "," << var.m_v[1] //打印个体速度
<<"fitness:" << var.m_fitness << endl; //打印适应值
cout << "globle best:" << CalculateFitness(gbest) << endl; //打印全局最优点的适应值
}
double RandReal(int left, int right) { //函数:得到一个随机实数
int range = right - left; //计算右界和左界的差值
double result(0); //定义返回变量
result = rand() % range + (float)(rand() % 1000) / 1000.0 + left; //计算得到一个范围内的随机实数值
return result; //返回结果
}
double RandInt(int left, int right) { //函数:得到一个随机整数
int range = right - left; //计算右界和左界的差值
double result(0); //定义返回变量
result = rand() % (range + 1) + left; //计算得到一个范围内的随机实数值
return result; //返回结果
}
void InitPop(){ //函数:得到一个
for(int i = 0; i < SIZE; i++){ //遍历每个个体
for (int j = 0; j < DIMENSION; j++){ //遍历个体的每一维
population[i].m_x[j] = RandReal(LOWER_BOUND[j], UPPER_BOUND[j]); //初始化位置
population[i].m_v[j] = RandReal(MIN_VELO[j], MAX_VELO[j]); //初始化速度
}
population[i].m_fitness = CalculateFitness(population[i].m_x); //计算适应值
population[i].m_pbest = population[i].m_x; //一开始的最优点就是第一个点
}
}
double CalculateFitness(vector<double>x){ //函数:计算适应值
double result(0); //定义返回变量
result = x[0] * x[0] + x[1] * x[1]; //目标函数f=x1^2+y^2
return result; //返回结果
}
void FreshVelocity(int i){ //函数:更新速度
double r1 = RandReal(0, 1); //定义随机数1
double r2 = RandReal(0, 1); //定义随机数2
for (int j = 0; j < DIMENSION; j++){ //遍历个体的每一维
population[i].m_v[j] = //更新速度
W*population[i].m_v[j] + //第一项,惯性系数乘原速度
C1*r1*(population[i].m_pbest[j] - population[i].m_x[j]) + //第二项,个体认知影响
C2*r2*(gbest[j] - population[i].m_x[j]); //第三项,社会经验影响
if (population[i].m_v[j] < MIN_VELO[j]) //如果速度向下越界
population[i].m_v[j] = MIN_VELO[j]; //速度被赋为下界限值
if (population[i].m_v[j] > MAX_VELO[j]) //如果速度向上越界
population[i].m_v[j] = MAX_VELO[j]; //速度被赋为上界限值
}
}
void FreshPosition(int i) { //函数:更新位置
for (int j = 0; j < DIMENSION; j++){ //遍历个体的每一维
population[i].m_x[j] += population[i].m_v[j]; //新的位置为原位置加速度
if (population[i].m_x[j] < LOWER_BOUND[j]) //如果位置向下越界
population[i].m_x[j] = LOWER_BOUND[j]; //位置被赋为下界限值
if (population[i].m_x[j] > UPPER_BOUND[j]) //如果位置向上越界
population[i].m_x[j] = UPPER_BOUND[j]; //位置被赋为上界限值
}
population[i].m_fitness = CalculateFitness(population[i].m_x); //更新适应值
}