粒子群算法

news2024/11/14 16:42:14

粒子群算法

  • 1 粒子群算法介绍
  • 2 基本思想
  • 3 算法流程
  • 4 代码实现

1 粒子群算法介绍

粒子群优化算法(PSO:Particle swarm optimization) 是一种进化计算技术(evolutionary computation)。源于对鸟群捕食的行为研究。粒子群优化算法的基本思想是通过群体中个体之间的协作和信息共享来寻找最优解。

PSO的优势在于简单容易实现并且没有许多参数的调节,收敛速度快。目前已被广泛应用于函数优化、神经网络训练、模糊系统控制以及其他遗传算法的应用领域。

相关概念:
在这里插入图片描述
适应度函数:来判断当前位置对粒子的吸引力,适应度函数值越大,位置就越好,对粒子的吸引力就越大,那么这个适应度函数值就越有可能是最优解。

2 基本思想

粒子群算法源于对鸟类捕食行为的研究,基本原理是通过种群中个体的信息共享以及协作筛选来寻求最优解。粒子仅具有两个属性:速度和位置,速度是矢量,包括速度大小和方向,位置表示粒子当前所在的坐标。系统首先初始化一组粒子种群,每个粒子都具有一个初始位置和速度,根据评价函数计算得到初始最优解,将其标记成当前个体极值,然后各个粒子之间通过协作共享信息得到群体极值并不断进行迭代,在每一次迭代得到新的个体极值和群体极值后通过下面的公式来更新自己的速度和位置。
在这里插入图片描述

公式(1)的第一部分称为“记忆项”,表示上次速度大小和方向的影响;公式(1)的第二部分称为“个体认知项”,表示粒子在解空间有朝着过去曾经碰到的最优解进行搜索的趋势;公式(1)的第三部分称为“群体认知项”,表示粒子在解空间有朝着整个邻域曾经碰到过的最优解进行搜索的趋势,反映了粒子间的协同合作和知识共享。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。

1998年,Shi和Eberhart引入了惯性权重w,并提出动态调整惯性权重以平衡收敛的全局性和收敛速度,该算法被称为标准PSO算法。
在这里插入图片描述

参数详细分析:

  • 群体规模N:粒子群中粒子的总数,一般取20~40,对较难或特定类别的问题可以取到100~200。
  • 速度,Vi是粒子的速度,最大速度Vmax(大于0),决定当前位置与最好位置之间的区域的分辨率(或精度)。如果Vmax太快,则搜索能力增强,但是粒子容易错过最优解,Vmax较小,开发能力增强,但是粒子容易陷入局部最优。Vmax一般设为每维变量变化范围的10%~20%。如果Vi大于Vmax,则Vi等于Vmax。
  • Xi是粒子的当前位置
  • rand()是介于(0,1)之间的随机数
  • 权重因子:包括惯性因子w和学习因子c1和c2。
    • 惯性因子w,其值非负,表示粒子上一代速度对当前代速度的影响,其值较大,全局寻优能力强,局部寻优能力弱,其值较小,全局寻优能力弱,局部寻优能力强。

      动态惯性因子能够获得比固定值更好的寻优结果。动态惯性因子可在PSO搜索过程中线性变化,也可以根据PSO性能的某个测度函数动态改变。目前采用较多的是线性递减权值策略。
      在这里插入图片描述
      Wmax是最大惯性权重,Wmin是最小惯性权重,run是当前迭代次数,run(max)是算法迭代总次数。当问题空间较大时,随着迭代次数的增加,惯性系数应当不断减少,从而使粒子群算法在初期具有较强的全局搜索能力,以尽可能地获得较大搜索范围,在后期具有较强的局部收敛能力以提高寻优精度。

      典型权值有0.9和0.4,分别是最大惯性权重和最小惯性权重

    • 个体认知因子和群体认知因子c1、c2。如果c1选的太大,就会造成个体认知对粒子的速度产生影响过大,即优先考虑自己认为的最好位置,如果c2选的过大,就会导致社会影响对粒子的速度影响过大,即优先考虑种群的最好位置,如果c1、c2选的过小,就说明,粒子自己当前飞行的速度大小和方向是最稳当的。如果c1 = 0,则只有社会,没有自我,太依赖群体,如果c2 = 0,只有自我认知,没有社会群体,这是最危险的,大家都觉得自己是最优的,都朝着自己认为对的方向飞,那么这个粒子群算法就失去了寻优的能力。如果c1=c2=0,粒子将一直以当前速度的飞行,直到边界。很难找到最优解。通常设c1=c2=2。
      当目标函数比较复杂时,普通的粒子群算法容易陷入局部最优,而且后期的收敛速度较慢,这会导致整个算法的效率和精度下降。影响粒子群算法的效率和精度的参数主要有惯性权重w、个体认知因子c1、群体认知因子c2。当w较大时,算法有着更好的全局搜索能力,当w较小时,算法有着更好的局部寻优能力;当c1较小、c2较大时,算法有着更好的局部寻优能力。恰当地选取算法的参数值可以改善算法的性能。

3 算法流程

在这里插入图片描述

我们尤其要注重把PSO与其它算法,如进化算法、模糊逻辑、生物智能以及混沌等方法或策略相结合,解决PSO易陷入局部最优的问题。

4 代码实现

具体代码如下:

1、定义参数

#define PI 3.14159265358979323846
#define POPSIZE 20                         //粒子个数
#define MAXINTERATION 2000                 //最大迭代次数
#define NVARS 10                           //参数个数
#define WMAX 0.9                           //惯量权重最大值
#define WMIN 0.4                           //惯量权重最小值
 
struct particle {                          //单个粒子
	double pBest[NVARS];
	double v[NVARS];
	double x[NVARS];
	double upper[NVARS];
	double lower[NVARS];
};
 
double w;                                  //惯量权重
double c1 = 2.0;                           //加速因子1
double c2 = 2.0;                           //加速因子2
double absbound;                           //上下界绝对值
double vmax;                               //最大速度
double gBest[NVARS];                       //全局最优解
particle particles[POPSIZE];               //粒子群

2、函数定义

double evalfunc(double[], int);            //评估函数
double avg(double[], int);                 //求平均数
double stddev(double[], int);              //求标准差
void initialize(int);                      //初始化函数
double randval(double, double);            //求范围(lower,upper)之间的随机数
void evaluate(int);                        //评估粒子适应值
void update(int, int);                     //利用更新公式更新每个粒子的速度和位置以及历史最优位置
void fit(void);                            //更新群体历史最优位置

3、评估函数

double evalfunc(double parameter[], int FUNC = 1) {
	/*          10个评估函数            */
	/* 通过参数FUNC来选择想要的评估函数 */
	if (FUNC == 1) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += parameter[i] * parameter[i];
		}
		return val;
	}
 
	if (FUNC == 2) {
		double val1 = 0;
		double val2 = 0;
		for (int i = 0; i < NVARS; i++) {
			val1 += abs(parameter[i]);
			val2 = val2*abs(parameter[i]);
		}
		return (val1 + val2);
	}
 
	if (FUNC == 3) {
		double val1 = 0;
		int i, j;
		for (i = 0; i < NVARS; i++) {
			double val2 = 0;
			for (j = 0; j < i; j++) {
				val2 += parameter[j];
			}
			val1 += val2*val2;
		}
		return val1;
	}
 
	if (FUNC == 4) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			if (abs(parameter[i]) > val)
				val = abs(parameter[i]);
		}
	}
 
	if (FUNC == 5) {
		double val = 0;
		for (int i = 0; i < NVARS - 1; i++) {
			val += 100 * (parameter[i + 1] - parameter[i] * parameter[i])*(parameter[i + 1] - parameter[i] * parameter[i]) + (parameter[i] - 1)*(parameter[i] - 1);
		}
		return val;
	}
 
	if (FUNC == 6) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += floor(parameter[i] + 0.5)*floor(parameter[i] + 0.5);
		}
		return val;
	}
 
	if (FUNC == 7) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += i*pow(parameter[i], double(i));
		}
		return (val + randval(0, 1));
	}
 
	if (FUNC == 8) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += (-(parameter[i] * sin(sqrt(abs(parameter[i])) / 180 * PI)));
		}
		return val;
	}
 
	if (FUNC == 9) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += (parameter[i] * parameter[i] - 10 * cos(2 * PI*parameter[i] / 180 * PI) + 10.0);
		}
		return val;
	}
 
	if (FUNC == 10) {
		double val1 = 0;
		double val2 = 0;
		for (int i = 0; i < NVARS; i++) {
			val1 += parameter[i] * parameter[i];
			val2 += cos(2 * PI*parameter[i] / 180 * PI);
		}
		return ((-20)*exp((-0.2)*sqrt(val1 / NVARS)) - exp(val2 / NVARS) + 20 + exp(1));
	}
}

4、一些计算指标及随机数函数

double avg(double parameter[], int n) {
	double num = 0;
	for (int i = 0; i < n; i++) {
		num += parameter[i];
	}
	return num / n;
}
 
 
double stddev(double parameter[], int n) {
	double num = avg(parameter, n);
	double sum = 0.0;
	for (int i = 0; i < n; i++) {
		sum += (parameter[i] - num)*(parameter[i] - num);
	}
	return sqrt(sum / n);
}
 
 
double randval(double low, double high) {
	return (low + (high - low)*rand()*1.0 / RAND_MAX);
}

5、初始化函数

void initialize(int FUNC = 1) {
	/*  初始化每个粒子的速度、位置并将  */
	/*  该位置设定为当前历史最优位置找  */
	/*  到所有粒子的最优位置并设定为当  */
	/*  前群体历史最优位置              */
	int i, j;
	double lbound[NVARS];
	double ubound[NVARS];
 
	for (i = 0; i < NVARS; i++) {
		lbound[i] = (-absbound);
		ubound[i] = absbound;
	}
 
	for (i = 0; i < NVARS; i++) {
		for (j = 0; j < POPSIZE; j++) {
			particles[j].upper[i] = ubound[i];
			particles[j].lower[i] = lbound[i];
			particles[j].v[i] = randval(lbound[i], ubound[i]);
			particles[j].x[i] = randval(lbound[i], ubound[i]);
			particles[j].pBest[i] = particles[j].x[i];
		}
	}
 
	double pval = evalfunc(particles[0].pBest);
	int num;
	for (i = 1; i < POPSIZE; i++) {
		if (pval > evalfunc(particles[i].pBest)) {
			pval = evalfunc(particles[i].pBest);
			num = i;
		}
		else continue;
	}
	for (j = 0; j < NVARS; j++) {
		gBest[j] = particles[num].pBest[j];
	}
}

6、评估

void evaluate(int FUNC = 1) {
	/*  通过传入参数FUNC来调用不同的评  */
	/*  估函数并对粒子位置进行评估并更  */
	/*  新粒子历史最优位置              */
	int i, j;
	double pval[POPSIZE], nval[POPSIZE];
 
	for (i = 0; i < POPSIZE; i++) {
		pval[i] = evalfunc(particles[i].pBest, FUNC);
		nval[i] = evalfunc(particles[i].x, FUNC);
 
		if (pval[i] > nval[i]) {
			for (j = 0; j < NVARS; j++) {
				particles[i].pBest[j] = particles[i].x[j];
			}
		}
	}
}

7、更新函数

void update(int interation, int w_change_method = 1) {
	/*  通过参数w_change_method来选择不 */
	/*  同的惯性权重衡量规则来根据群体  */
	/*  历史最优位置更新粒子速度以及位置*/
	int i, j;
	double v, x;
 
	if (w_change_method == 1) {
		w = WMAX - (WMAX - WMIN) / MAXINTERATION*(double)interation;
	}
	else if (w_change_method == 2) {
		w = randval(0.4, 0.6);
	}
	else if (w_change_method == 3) {
		w = WMAX - (WMAX - WMIN)*((double)interation / MAXINTERATION)*((double)interation / MAXINTERATION);
	}
	else if (w_change_method == 4) {
		w = WMIN + (WMAX - WMIN)*((double)interation / MAXINTERATION - 1)*((double)interation / MAXINTERATION - 1);
	}
	else {
		cout << "Dont have this weight change method!";
		return;
	}
 
	for (i = 0; i < NVARS; i++) {
		for (j = 0; j < POPSIZE; j++) {
			v = w*particles[j].v[i] + c1*randval(0, 1)*(particles[j].pBest[i] - particles[j].x[i]) + c2*randval(0, 1)*(gBest[i] - particles[j].x[i]);
			if (v > vmax)particles[j].v[i] = vmax;
			else if (v < (-vmax))particles[j].v[i] = (-vmax);
			else particles[j].v[i] = v;
 
			x = particles[j].x[i] + particles[j].v[i];
			if (x > particles[j].upper[i])particles[j].x[i] = particles[j].upper[i];
			else if (x < particles[j].lower[i])particles[j].x[i] = particles[j].lower[i];
			else particles[j].x[i] = x;
		}
	}
}

8、适应函数

void fit(void) {
	/*         更新群体最优位置         */
	int i, j;
	double gval = evalfunc(gBest);
	double pval[POPSIZE];
 
	for (i = 0; i < POPSIZE; i++) {
		pval[i] = evalfunc(particles[i].pBest);
 
		if (gval > pval[i]) {
			for (j = 0; j < NVARS; j++) {
				gBest[j] = particles[i].pBest[j];
			}
		}
	}
}

9、main函数

int main() {
	srand(time(NULL));
	double all_gBest[100];
	int i, j, k;
	int FUNC;
	int w_change_method;
	cout << "*********************************************************************************************************************************" << endl;
	cout << "*******************************  十个" << NVARS << "维函数用4种不同的权重控制方法运行一百次的平均结果及标准差" << "  *******************************" << endl;
	cout << "                线性递减法" << "                      随机权重法" << "                      凹函数递减法" << "                    凸函数递减法" << endl;
	cout << " 函数" << endl;
	cout << "           平均值" << "          标准差"
		<< "          平均值" << "          标准差"
		<< "          平均值" << "          标准差"
		<< "          平均值" << "          标准差";
	cout << endl << endl;
	for (FUNC = 1; FUNC <= 10; FUNC++) {
		cout << " " << std::left << "f" << setw(4) << FUNC;
		switch (FUNC)
		{
		case 1:absbound = 100.0; break;
		case 2:absbound = 10.0; break;
		case 3:absbound = 100.0; break;
		case 4:absbound = 100.0; break;
		case 5:absbound = 30.0; break;
		case 6:absbound = 100.0; break;
		case 7:absbound = 1.28; break;
		case 8:absbound = 500.0; break;
		case 9:absbound = 5.12; break;
		case 10:absbound = 32.0; break;
		default:
			break;
		}
		vmax = absbound*0.15;
		for (w_change_method = 1; w_change_method <= 4; w_change_method++) {
			for (j = 0; j < 100; j++) {
				initialize();
				evaluate(FUNC);
				for (int i = 0; i < MAXINTERATION; i++) {
					update(i, w_change_method);
					evaluate(FUNC);
					fit();
				}
				double evalue = evalfunc(gBest);
				if (evalue == 0) {
					j--;
					continue;
				}
				all_gBest[j] = evalue;
			}
			cout << setw(16) << avg(all_gBest, 100);
			cout << setw(16) << stddev(all_gBest, 100);
		}
		cout << endl;
	}
	cout << "*********************************************************  算法运行结束  ********************************************************" << endl;
	cout << "*********************************************************************************************************************************" << endl;
	system("pause");
}

参考资料:https://blog.csdn.net/darin1997/article/details/80675933?spm=1001.2014.3001.5506

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/393052.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我建议,专家不要再建议了

作者| Mr.K 编辑| Emma来源| 技术领导力(ID&#xff1a;jishulingdaoli)关于买房&#xff0c;专家建议&#xff1a;不建议掏空六个钱包凑首付。&#xff08;网友&#xff1a;丈母娘等不到我自己挣够&#xff09;关于农村剩男多&#xff0c;城市剩女多&#xff0c;专家建议&am…

Adobe illustrator学习笔记

Adobe illustrator学习笔记 生命有限&#xff0c;设计无限 学习Adobe illustrator主要是用来制作SVG图片去制作字体图标&#xff0c;因此笔记内容大多会围绕SVG展开。 2023-3-5 1、Adobe illustrator简介 主要用于制作矢量图和插图 2、颜色模式介绍 显示颜色&#xff1a;RGB…

EXCEL里的各种奇怪计算问题:数字后面自动多了 0.0001, 数字后面位数变成000,以及一些取整,数学函数

1 公式计算后的数&#xff0c;用只粘贴数值后&#xff0c;后面自动多了 0.0001&#xff0c;导致不再是整数的问题 问题入戏 见第1个8400&#xff0c;计算时就出现了问题&#xff0c;按正常&#xff0c;这里8400应该是整数&#xff0c;而不应该带小数&#xff0c;但是确实就计…

我不写单元测试,被批了

我是3y&#xff0c;一年CRUD经验用十年的markdown程序员&#x1f468;&#x1f3fb;‍&#x1f4bb;常年被誉为职业八股文选手最近在看单元测试的东西&#xff0c;想跟大家聊聊我的感受。单元测试这块说实在的&#xff0c;我并不太熟悉&#xff0c;我几乎不写单元测试&#xff…

项目中维护一个随时更新的ui库的解决方案之一(uniapp+uview-plus)

1. 环境准备 需要准备两个仓库&#xff0c;第一个仓库用来存uniapp项目的相关代码&#xff0c;第二个用来存放uview-plus UI库的代码&#xff08;第二个仓库的仓库名称为uview-plus&#xff09; 2. 项目结构 我们uniapp目录结构大致如下 我们维护的ui组件应该是uni_modules下…

详解JAVA类加载器

目录 1.概述 2.双亲委派 3.ServiceClassLoader 4.URLClassLoader 5.加载冲突 1.概述 概念&#xff1a; 类加载器&#xff08;Class Loader&#xff09;是Java虚拟机&#xff08;JVM&#xff09;的一个重要组件&#xff0c;负责加载Java类到内存中并使其可以被JVM执行。类…

抢先看!界面控件DevExtreme 2023产品路线图曝光

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…

【C++】优先级队列 priority_queue,仿函数和函数对象,反向迭代器

目录 1.介绍和实现 2.仿函数和函数对象 3.oj 4.反向迭代器 1.介绍和实现 他也在<queue>的头文件里 但是他的底层是堆&#xff0c;并不满足先入先出&#xff08;不要一看到queue就先入先出&#xff09; 他也是一个容器适配器&#xff0c;用vector适配的&#xff0c;为…

利用Qemu工具仿真ARM64平台

Windows系统利用Qemu仿真ARM64平台0 写在最前1 Windows安装Qemu1.1 下载Qemu1.2 安装Qemu1.3 添加环境变量1.4测试安装是否成功2. Qemu安装Ubuntu-Server-Arm-642.1 安装前的准备2.2 安装Ubuntu server arm 64位镜像3 Windows配置Qemu网络和传输文件3.1 参考内容3.2 Windows安装…

数据湖架构Hudi(五)Hudi集成Flink案例详解

五、Hudi集成Flink案例详解 5.1 hudi集成flink flink的下载地址&#xff1a; https://archive.apache.org/dist/flink/ HudiSupported Flink version0.12.x1.15.x、1.14.x、1.13.x0.11.x1.14.x、1.13.x0.10.x1.13.x0.9.01.12.2 将上述编译好的安装包拷贝到flink下的jars目录…

Python(青铜时代)——字符串

字符串的定义与操作 字符串就是 一串字符 &#xff0c;是编程语言中表示文本的数据类型 在Python中使用一对双引号 "" 或者一对单引号来定义. 使用索引获取一个字符串中 指定位置的字符&#xff0c;索引计数从0开始 可以用 for/while 循环遍历字符串中的每一个字符…

NGINX学习笔记(一):一篇了解NGINX的基本概念

NGINX是什么&#xff1f; NGINX是一款由俄罗斯人伊戈尔赛索耶夫使用C语言开发的、支持热部署的、轻量级的WEB服务器/反向代理服务器/电子邮件代理服务器&#xff0c;因为占用内存较少&#xff0c;启动极快&#xff0c;高并发能力强&#xff0c;所以在互联网项目中广泛应用。可…

CRM系统的四种数据分析法

在数字化时代&#xff0c;数据就是一切。因此&#xff0c;通过数据来支撑企业决策&#xff0c;才能确保制定的决策在更大程度上保持准确。因此&#xff0c;CRM客户管理系统的数据分析能力不容忽略。CRM获取的客户信息&#xff0c;就是很好的数据支撑样本&#xff0c;让企业从数…

CANfd 一次采样点和二次采样点

CANfd 一次采样点和二次采样点 采样点的定义 采样点是CAN控制器读取总线电平&#xff0c;并解释各个比特的逻辑值的时间点。 首先我们需要了解Tq的概念&#xff0c;Tq是can控制器的最下时间周期称作时间份额&#xff08;Time quantum&#xff0c;简称Tq&#xff09;,它是通过芯…

2023年3月全国DAMA-CDGA/CDGP数据治理认证招生简章

弘博创新是DAMA中国授权的数据治理人才培养基地&#xff0c;贴合市场需求定制教学体系&#xff0c;采用行业资深名师授课&#xff0c;理论与实践案例相结合&#xff0c;快速全面提升个人/企业数据治理专业知识与实践经验&#xff0c;通过考试还能获得数据专业领域证书。 DAMA认…

嵌入式学习笔记——认识STM32的 GPIO口

寄存器开发STM32GPIO口前言认识GPIOGPIO是什么GPIO有什么用GPIO怎么用STM32上GPIO的命名以及数量GPIO口的框图&#xff08;重点&#xff09;输入框图解析三种输入模式GPIO输入时内部器件及其作用1.保护二极管2.上下拉电阻&#xff08;可配置&#xff09;3.施密特触发器4.输入数…

Spark 存储系统

Spark 存储系统MemoryStoreDiskStoreSpark 存储系统架构&#xff1a; Spark 存储系统维护的数据 : Shuffle 中间文件 &#xff1a;Shuffle Map 输出数据 &#xff0c; 消耗节点磁盘广播变量 &#xff1a;在 Executors 内保存所有数据 &#xff0c;消耗节点的内存RDD Cache : 将…

大数据技术之Hive(五)拉链表的设计与实现

一、什么是拉链表针对订单表、订单商品表&#xff0c;流水表&#xff0c;这些表中的数据是比较多的&#xff0c;如果使用全量的方式&#xff0c;会造成大量的数据冗余&#xff0c;浪费磁盘空间。所以这种表&#xff0c;一般使用增量的方式&#xff0c;每日采集新增的数据。在这…

DevOps平台之GitLab 账户个性化设置【二】

1、简介 上一篇文章安装完GITLAB服务之后&#xff0c;我们可以很方便地从浏览器登录上去进行仓库项目管理。 但是初始化的界面默认设备并不是能很好地使用&#xff0c;比如语言&#xff0c;皮肤&#xff0c;个人信息不完善等等。 所以本文就为了完善这些。 上一篇&#xff1a;…

Linux 配置本地yum源

挂载光盘 进入包 配置路径&#xff0c;查看在线yum源 移动在线yum源到/home/目录下 进入vi,任意取名以.repo结尾即可 按住i进行编辑&#xff0c;输入以下内容 注意gpgcheck1是检验&#xff0c;配置本地yum源不需要检验 写入上图内容按住&#xff1a;输入wq&#xff0c;点击回车…