C++类:粒子群算法

博主自制了一个粒子群算法类,通过识别输入函数指针自动匹配目标函数并迭代。该类改进后无需额外库,仅需三个C++系统头文件。文中给出利用该类求解函数最小值的示例代码,还说明了目标函数计算及维度扩展方法。

自己写了一个粒子群算法类,使用非常方便,供大家学习使用。通过识别输入的函数指针,该类会自动匹配目标函数,并进行迭代,因此方便使用。在原文上进行了改进,无需使用其他额外的库即可实现算法,该类的实现只需包含三个C++系统头文件(<vector>、<iostream>、<windows>)

目录

接口函数使用:

示例代码:

示例结果:

源代码:

ParticleSwarm.h

ParticleSwarm.cpp

目标函数计算的说明:


类中的函数使用

void setParticleSwarm()设置粒子群参数
void Iteration()粒子群迭代
std::vector<double> getResult()得到结果
void printResult()查看结果

利用该类求解函数最小值的示例代码

        在以下的代码中,利用该粒子群类求解了当目标函数:valueFunc(x,y,z)  的函数值取得最小时对应的变量x、y、z的最优取值。在本示例代码中,建立了一个粒子群对象:thisPSO,并使用了二维容器变量:limits,通过对limits的赋值设置了求解时的函数参数取值范围为:(x,y,z)\in[-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(...);)中加几个输入即可。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伪程序猿l S x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值