自己写了一个粒子群算法类,使用非常方便,供大家学习使用。通过识别输入的函数指针,该类会自动匹配目标函数,并进行迭代,因此方便使用。在原文上进行了改进,无需使用其他额外的库即可实现算法,该类的实现只需包含三个C++系统头文件(<vector>、<iostream>、<windows>)
目录
类中的函数使用
| void setParticleSwarm() | 设置粒子群参数 |
| void Iteration() | 粒子群迭代 |
| std::vector<double> getResult() | 得到结果 |
| void printResult() | 查看结果 |
利用该类求解函数最小值的示例代码
在以下的代码中,利用该粒子群类求解了当目标函数:valueFunc(x,y,z) 的函数值取得最小时对应的变量x、y、z的最优取值。在本示例代码中,建立了一个粒子群对象:thisPSO,并使用了二维容器变量:limits,通过对limits的赋值设置了求解时的函数参数取值范围为:(x,y,z)[-4,4]×[-4,4]×[-4,4],利用类中的函数:setParticleSwarm() 设置了求解时的参数(粒子数目:30;迭代次数:1000;粒子惯性系数:0.9;自我学习系数:0.6;社会学习系数:0.6),在设置了参数后,使用类中的函数:Iteration() 将目标函数名传入该函数并按照指定的参数运算,最后利用函数:printResult() 打印出了求解结果以及一些求解信息。
#include"ParticleSwarm.h"
double valueFunc(double x, double y, double z) {//测试使用的目标函数
return std::pow(x - 1.0, 2.0) + std::pow(y - 3.0, 2.0) + std::pow(z - 1.5, 2.0);
}
void main() {
ParticleSwarm thisPSO;//建立一个粒子群,可以在此步调用其构造函数直接设置参数
std::vector<std::vector<double>> limits;//粒子活动的界限,是一个 dimension × 2 的矩阵,每一行的2个参数代表了粒子解空间在这一维度的取值范围
std::vector<double> x_region, y_region, z_region;//为了给上一行的 limits 赋值,首先需要将每个纬度的取值范围单独写出来
x_region.push_back(-4.0); x_region.push_back(4.0);//设置 x 的取值范围为:[-4.0 , 4.0]
y_region.push_back(-4.0); y_region.push_back(4.0);//设置 y 的取值范围为:[-4.0 , 4.0]
z_region.push_back(-4.0); z_region.push_back(4.0);//设置 z 的取值范围为:[-4.0 , 4.0]
limits.push_back(x_region);
limits.push_back(y_region);
limits.push_back(z_region);//对 limits 进行赋值:将每一维度的取值范围推入(调用 push_back()即可),粒子群会自动识别维度数
thisPSO.setParticleSwarm(30, 1000, limits, 0.9, 0.6, 0.6);//设置粒子群参数:粒子数目 = 30 ; 迭代次数 = 1000 ; 粒子的运动范围 = limits ; 粒子的惯性系数 = 0.9 ; 粒子的个体学习系数 = 0.6 ; 粒子的社会学习系数 = 0.6。
thisPSO.Iteration(valueFunc);//迭代:将目标函数名传入函数即可。粒子群会自动识别函数的输入参数数目,目前支持 1 ~ 4 维的目标函数,如果需要更多维度的目标函数可以在类中添加代码,并且只需做很小的改动
thisPSO.printResult();//显示结果:显示求解结果
}
示例结果
该结果是函数:printResult() 所打印的。

源代码
头文件:ParticleSwarm.h
#pragma once
#include<vector>
#include<iostream>
#include"windows.h"
/**生成在两个数之间(包含两个数的随机整数)
@param valueLow 数据下界
@param valueHigh 数据上界
*/
int Random(int valueLow, int valueHigh);
/**生成在两个数之间(包含两个数的随机整数),精度为五位小数
@param valueLow 数据下界
@param valueHigh 数据上界
*/
double Random(double valueLow, double valueHigh);
/*单个粒子类*/
class OneParticle {
public:
double value = 0;
std::vector<double> positionVector;//在多维空间中的当前多维位置向量,由使用者定义
std::vector<double> speed;//粒子当前的多维速度
std::vector<std::vector<double>> historyPosition;//历史上的位置
std::vector<double> valueVector;//每次迭代时的函数值
std::vector<double> GetBestValuePosition();//得到历史最优函数取值处的坐标
double GetBestValue();//得到历史最佳点位置的函数取值
/**更新粒子的位置
@param history_GlobalBestPosition 自迭代开始以来粒子群中得到最佳函数取值的粒子位置向量
@param limits 粒子位置的界限,是一个dim x 2的矩阵,每一行表示了粒子一个纬度中的界限
@param omega 惯性系数
@param selfIndex 粒子个体学习因子
@param globalIndex 粒子社会学习因子
*/
void PositionUpdate(std::vector<double> history_GlobalBestPosition, std::vector<std::vector<double>> limits, double omega = 0.9, double selfIndex = 1.0, double globalIndex = 1.5);
/*在界限中随机放置粒子*/
void RandomPosition(std::vector<std::vector<double>> limits);
private:
std::vector<double> selfBestPosition;
};
/*粒子群类,求解的是函数的最小值对应的点位置*/
class ParticleSwarm {
public:
/**设置粒子群参数
@param dimension 粒子群所在空间的维数
@param maxIteration 最大迭代次数
@param limits 粒子位置的界限,是一个dim x 2的矩阵,每一行表示了粒子一个纬度中的界限
@param omega 粒子惯性系数,推荐取值范围[0.4, 0.9]
@param selfIndex 个体学习因数,推荐取值范围[0.4, 1.2]
@param globalIndex 社会学习因数,推荐取值范围[0.4, 1.2]
*/
void setParticleSwarm(int particleNumber, int maxIteration, std::vector<std::vector<double>> limits, double omega = 0.9, double selfIndex = 0.6, double globalIndex = 0.6);
/**粒子群迭代
@param ValueFunction 迭代的目标函数
*/
void Iteration(double (*ValueFunction)(double value11));
/**粒子群迭代
@param ValueFunction 迭代的目标函数
*/
void Iteration(double (*ValueFunction)(double value21, double value22));
/**粒子群迭代
@param ValueFunction 迭代的目标函数
*/
void Iteration(double (*ValueFunction)(double value31, double value32, double value33));
/**粒子群迭代
@param ValueFunction 迭代的目标函数
*/
void Iteration(double (*ValueFunction)(double value41, double value42, double value43, double value44));
/*得到粒子群迭代的结果*/
std::vector<double> getResult();
/*打印结果*/
void printResult();
ParticleSwarm(int particleNumber, int maxIteration, std::vector<std::vector<double>> limits, double omega = 0.9, double selfIndex = 0.6, double globalIndex = 0.6);
ParticleSwarm();
private:
std::vector<OneParticle> particleSet;//粒子集合
int dimension = 2, maxIterationNumber = 1000;
bool isSet = FALSE;//参数是否被设置的标志位
double selfIndex = 1.0, globalIndex = 1.5, omega = 0.9;
clock_t startTime = 0, endTime = 0;
std::vector<std::vector<double>> limits;//数据取值界限
OneParticle allTimeBestPosition;//自迭代开始以来的全局最优位置
/**
得到最佳参数取值处的位置,需要首先得到粒子目标函数值,该函数更新了粒子的最佳位置,
并将最优的粒子放置于this->allTimeBestPosition
*/
void allTimeBestPosition_Update();
/*随机放置粒子*/
void putParticle();
};
源文件:ParticleSwarm.cpp
#include"ParticleSwarm.h"
int Random(int valueLow, int valueHigh) {
return (rand() % (valueHigh - valueLow + 1)) + valueLow;
}
double Random(double valueLow, double valueHigh) {
return (0.1 * Random(0, 9) + 0.01 * Random(0, 9) + 0.001 * Random(0, 9) + 0.0001 * Random(0, 9) + 0.00001 * Random(0, 9)) * (valueHigh - valueLow) + valueLow;
}
std::vector<double> OneParticle::GetBestValuePosition() {
int minPosition = 0;
double minValue = this->valueVector[minPosition];
for (int i = 0; i < this->valueVector.size(); i++) {
if (this->valueVector[i] < minValue) {
minValue = this->valueVector[i];
minPosition = i;
}
}
this->selfBestPosition = this->historyPosition[minPosition];
return this->historyPosition[minPosition];
}
double OneParticle::GetBestValue() {
int minPosition = 0;
double minValue = this->valueVector[minPosition];
for (int i = 0; i < this->valueVector.size(); i++) {
if (this->valueVector[i] < minValue) {
minValue = this->valueVector[i];
minPosition = i;
}
}
return minValue;
}
void OneParticle::PositionUpdate(std::vector<double> history_GlobalBestPosition, std::vector<std::vector<double>> limits, double omega, double selfIndex, double globalIndex) {
std::vector<double> speedVector;
std::vector<double> globalPosition;
std::vector<double> selfBestPosition;
std::vector<double> thisPosition;
double self_radom_value = Random(double(0.0), double(1.0));
double global_radom_value = Random(double(0.0), double(1.0));
speedVector.resize(this->speed.size()); globalPosition.resize(this->speed.size());
selfBestPosition.resize(this->speed.size()); thisPosition.resize(this->speed.size());
/*速度更新*/
this->historyPosition.push_back(this->positionVector);
this->GetBestValuePosition();
for (int i = 0; i < this->speed.size(); i++) {
speedVector[i] = this->speed[i];//当前速度
globalPosition[i] = history_GlobalBestPosition[i];//所有粒子的全局最优位置
selfBestPosition[i] = this->selfBestPosition[i];//粒子个体最优位置
thisPosition[i] = this->positionVector[i];//粒子当前速度
}
for (int i = 0; i < speedVector.size(); i++) {
speedVector[i] = omega * speedVector[i] + selfIndex * self_radom_value * (selfBestPosition[i] - thisPosition[i]) + \
globalIndex * global_radom_value * (globalPosition[i] - thisPosition[i]);
}
/*位置更新*/
for (int i = 0; i < speedVector.size(); i++) {
thisPosition[i] += speedVector[i];
}
/*界限检验*/
for (int i = 0; i < this->speed.size(); i++) {
if (thisPosition[i] < limits[i][0] || thisPosition[i] > limits[i][1]) {
thisPosition[i] = Random(limits[i][0], limits[i][1]);
}
}
/*赋值*/
for (int i = 0; i < this->speed.size(); i++) {
this->speed[i] = speedVector[i];
this->positionVector[i] = thisPosition[i];
}
}
void OneParticle::RandomPosition(std::vector<std::vector<double>> limits) {
this->speed.resize(limits.size());
for (int i = 0; i < limits.size(); i++) {
this->positionVector.push_back(Random(double(limits[i][0]), double(limits[i][1])));
}
}
void ParticleSwarm::setParticleSwarm(int particleNumber, int maxIteration, std::vector<std::vector<double>> limits, double omega, double selfIndex, double globalIndex) {
this->maxIterationNumber = maxIteration;
this->limits = limits;
this->particleSet.resize(particleNumber);
this->isSet = TRUE;
this->omega = omega; this->selfIndex = selfIndex; this->globalIndex = globalIndex;
}
void ParticleSwarm::allTimeBestPosition_Update() {
double minValue = this->particleSet[0].value;
int bestPosition = 0;
for (int i = 0; i < this->particleSet.size(); i++) {
if (this->particleSet[i].value < minValue) {//找更小的值
minValue = this->particleSet[i].value;
bestPosition = i;
}
}
this->allTimeBestPosition = this->particleSet[bestPosition];
}
void ParticleSwarm::putParticle() {
for (int i = 0; i < this->particleSet.size(); i++) {
this->particleSet[i].RandomPosition(this->limits);
}
}
std::vector<double> ParticleSwarm::getResult() {
this->allTimeBestPosition_Update();
return this->allTimeBestPosition.positionVector;
}
ParticleSwarm::ParticleSwarm(int particleNumber, int maxIteration, std::vector<std::vector<double>> limits, double omega, double selfIndex, double globalIndex) {
this->setParticleSwarm(particleNumber, maxIteration, limits, omega, selfIndex, globalIndex);
}
ParticleSwarm::ParticleSwarm() {
}
void ParticleSwarm::Iteration(double (*ValueFunction)(double value11)) {
if (this->isSet) {
this->startTime = std::clock();
int iterationCount = 0;//迭代计数
/*放置粒子*/
this->putParticle();
/*迭代*/
while (iterationCount < this->maxIterationNumber) {
/*计算每个粒子的函数点值*/
for (int i = 0; i < this->particleSet.size(); i++) {
this->particleSet[i].value = ValueFunction(this->particleSet[i].positionVector[0]);
this->particleSet[i].valueVector.push_back(this->particleSet[i].value);
}
/*更新全局最优粒子点*/
this->allTimeBestPosition_Update();
/*粒子群位置更新*/
for (int i = 0; i < this->particleSet.size(); i++)
this->particleSet[i].PositionUpdate(this->allTimeBestPosition.positionVector, this->limits, this->omega, this->selfIndex, this->globalIndex);
iterationCount++;
}
this->endTime = std::clock();
}
}
void ParticleSwarm::Iteration(double (*ValueFunction)(double value21, double value22)) {
if (this->isSet) {
this->startTime = std::clock();
int iterationCount = 0;//迭代计数
/*放置粒子*/
this->putParticle();
/*迭代*/
while (iterationCount < this->maxIterationNumber) {
/*计算每个粒子的函数点值*/
for (int i = 0; i < this->particleSet.size(); i++) {
this->particleSet[i].value = ValueFunction(this->particleSet[i].positionVector[0], \
this->particleSet[i].positionVector[1]);
this->particleSet[i].valueVector.push_back(this->particleSet[i].value);
}
/*更新全局最优粒子点*/
this->allTimeBestPosition_Update();
/*粒子群位置更新*/
for (int i = 0; i < this->particleSet.size(); i++)
this->particleSet[i].PositionUpdate(this->allTimeBestPosition.positionVector, this->limits, this->omega, this->selfIndex, this->globalIndex);
iterationCount++;
}
this->endTime = std::clock();
}
}
void ParticleSwarm::Iteration(double (*ValueFunction)(double value31, double value32, double value33)) {
if (this->isSet) {
this->startTime = std::clock();
int iterationCount = 0;//迭代计数
/*放置粒子*/
this->putParticle();
/*迭代*/
while (iterationCount < this->maxIterationNumber) {
/*计算每个粒子的函数点值*/
for (int i = 0; i < this->particleSet.size(); i++) {
this->particleSet[i].value = ValueFunction(this->particleSet[i].positionVector[0], \
this->particleSet[i].positionVector[1], \
this->particleSet[i].positionVector[2]);
this->particleSet[i].valueVector.push_back(this->particleSet[i].value);
}
/*更新全局最优粒子点*/
this->allTimeBestPosition_Update();
/*粒子群位置更新*/
for (int i = 0; i < this->particleSet.size(); i++)
this->particleSet[i].PositionUpdate(this->allTimeBestPosition.positionVector, this->limits, this->omega, this->selfIndex, this->globalIndex);
iterationCount++;
}
this->endTime = std::clock();
}
}
void ParticleSwarm::Iteration(double (*ValueFunction)(double value41, double value42, double value43, double value44)) {
if (this->isSet) {
this->startTime = std::clock();
int iterationCount = 0;//迭代计数
/*放置粒子*/
this->putParticle();
/*迭代*/
while (iterationCount < this->maxIterationNumber) {
/*计算每个粒子的函数点值*/
for (int i = 0; i < this->particleSet.size(); i++) {
this->particleSet[i].value = ValueFunction(this->particleSet[i].positionVector[0], \
this->particleSet[i].positionVector[1], \
this->particleSet[i].positionVector[2], \
this->particleSet[i].positionVector[3]);
this->particleSet[i].valueVector.push_back(this->particleSet[i].value);
}
/*更新全局最优粒子点*/
this->allTimeBestPosition_Update();
/*粒子群位置更新*/
for (int i = 0; i < this->particleSet.size(); i++)
this->particleSet[i].PositionUpdate(this->allTimeBestPosition.positionVector, this->limits, this->omega, this->selfIndex, this->globalIndex);
iterationCount++;
}
this->endTime = std::clock();
}
}
void ParticleSwarm::printResult() {
char flags[50];
this->allTimeBestPosition_Update();
std::cout << "粒子数目:" << this->particleSet.size() << std::endl;
std::cout << std::endl;
std::cout << "总迭代次数:" << this->maxIterationNumber << std::endl;
std::cout << std::endl;
std::cout << "解空间维数:" << this->limits.size() << std::endl;
std::cout << std::endl;
std::cout << "求解时间(ms):" << this->endTime - this->startTime << std::endl;
std::cout << std::endl;
std::cout << "最优参数取值:" << std::endl;
std::cout << std::endl;
for (int i = 0; i < this->limits.size(); i++) {
sprintf_s(flags, "Param %d = ", i + 1);
std::cout << flags << this->allTimeBestPosition.positionVector[i] << std::endl;
}
}
目标函数计算的说明
目前该类仅支持1 ~ 4维的目标函数,如果需要更多维度,则需要添加一些代码,实际上仅需要添加函数 Iteration() 即可,例如需要一个维度为6的目标函数,则需要在代码中添加一个新的 Iteration()函数。读者可参考该类中其他 Iteration() 函数的写法,新添加的函数只需要在目标函数赋值语句(代码中的位置:this->particleSet[i].value = ValueFunction(...);)中加几个输入即可。
博主自制了一个粒子群算法类,通过识别输入函数指针自动匹配目标函数并迭代。该类改进后无需额外库,仅需三个C++系统头文件。文中给出利用该类求解函数最小值的示例代码,还说明了目标函数计算及维度扩展方法。

5800

被折叠的 条评论
为什么被折叠?



