烟花算法初探

前沿:函数优化求解问题学习过程中,不可避免选择求解算法,且不同的算法收敛速度不同,复杂度不同。探究问题求解的性能,则需要对求解算法进行对比。因此,在这里,引入烟花算法。

以下资料来源于书籍:《烟花算法引论》谭营 著;科学出版社,2015

1.烟花算法介绍

烟花算法初探_第1张图片
烟花算法初探_第2张图片
烟花算法初探_第3张图片

2.算法组成

烟花算法初探_第4张图片
烟花算法初探_第5张图片
烟花算法初探_第6张图片

3.算法实现

3.1 随机维度选择
随机维度选择是指在1和dim之间随机选择n个维度,且n个维度不重复。作用是在进行位移操作时对指定数量的位置进行偏移,即产生新的爆炸火花。
过程实现如下:

void DimensionRand(int dim, int num) {//num表示需要产生的维度个数
	for (int i = 0; i < dim; ++i) set_rand[i] = i;
	for (int j = dim - 1; j >= 1; --j) swap(set_rand[j], set_rand[rand() % j]);
}

3.2 爆炸算子
烟花算法初探_第7张图片
烟花算法初探_第8张图片
烟花算法初探_第9张图片
实现过程如下:

void Explosion() {
	//计算烟花适应度值
	for (int i = 0; i < fire_num; i++) {
		fitness[i] = Fitness(x_loc, i);
	}
	/*cout<

	//查询当前最优和最坏烟花个体
	fit_bad = fitness[0];
	fit_bad_index = 0;
	fit_best = fitness[0];
	fit_best_index = 0;
	for (int i = 0; i < fire_num;i++) {
		if (fitness[i] > fit_bad) {//查询最坏值
			fit_bad = fitness[i];
			fit_bad_index = i;
		}
		if (fitness[i] < fit_best) {//查询最坏值
			fit_best = fitness[i];
			fit_best_index = i;
		}
	}
	//cout << endl << "最坏值:" << fit_bad << endl<<"最好值:"<< fit_best<

	//计算火花个数
	double S_tem=0;
	for (int i = 0; i < fire_num;i++) {//计算分母
		S_tem += fit_bad - fitness[i];
	}
	for (int i = 0; i < fire_num;i++) {//计算火花数
		S_num[i] = fire_all * (fit_bad - fitness[i] + SMALL) / (S_tem+SMALL);
	}
	//cout <
	for (int i = 0; i < fire_num; i++) {//火花数限制取整
		if (S_num[i] < a*fire_all) 
			S_num[i] = round(a*fire_all);
		else if(S_num[i] > b*fire_all)
			S_num[i] = round(b*fire_all);
		else
			S_num[i] = round(S_num[i]);		
	}
	//cout <
	 
	//计算爆炸半径
	double A_tem = 0;
	for (int i = 0; i < fire_num; i++) {//计算分母
		A_tem += fitness[i]- fit_best;
	}
	for (int i = 0; i < fire_num; i++) {//计算火花数
		A_radius[i] = (int(10000*A_all * ( fitness[i]- fit_best + SMALL) / (A_tem + SMALL)))/10000.0;
	}
	srand((unsigned)time(NULL));
	for (int i = 0; i < fire_num;i++) {
		for (int k = 0; k < dim_num;k++) {//初始化维度集合
			set_rand[k] = -1;
		}
		srand((unsigned)time(NULL));
		for (int j = 0; j < S_num[i];j++) {
			DimensionRand(dim_num, set_num1);
			for (int k = 0; k < dim_num; k++) {
				if (k >= set_num1)
					set_rand[k] = -1;	
			}
			for (int k = 0; k < dim_num; k++) {
				spark[i][j][k] = x_loc[i][k];
			}
			for (int k = 0; k <set_num1; k++) {
				//计算位移
				h_offset = UniformDistribution(0.0,A_radius[i]);
				spark[i][j][set_rand[k]] = x_loc[i][set_rand[k]]+ h_offset;
				Mapping(spark,i,j, set_rand[k]);
			}
			
		}
	}
}

3.3 映射规则
产生的火花以及子代难免出现超出界限的情况,这时需要对界限进行操作;一种方法是:若位置超出界限,则重新随机生成;另一种方法是:若位置超出界限,则将其映射到界限以内。烟花算法则使用第二种方法。
烟花算法初探_第10张图片

void Mapping(double x1[fire_num][fire_all][dim_num], int fire, int S, int dim_k) {//输入位置集合、指定烟花和维度位置
	if (x1[fire][S][dim_k] != x_min * 10) {
		if ((x1[fire][S][dim_k] < x_min) || (x1[fire][S][dim_k] > x_max)) {
			double a1 = fabs(x1[fire][S][dim_k]);
			int a12 = int(a1 * 1000);
			double b1 = x_max - x_min;
			int b12 = int(b1 * 1000);
			x1[fire][S][dim_k] = x_min + double(a12 % b12) / 1000.0;
		}
	}
}

3.4 变异算子
烟花算法初探_第11张图片
烟花算法初探_第12张图片
实现过程如下:

void Mutation() {
	//产生变异位置
	for (int k = 0; k < dim_num; k++) {//初始化维度集合
		set_rand[k] = -1;
	}
	srand((unsigned)time(0));
	for (int i = 0; i < fire_num;i++) {
		srand((unsigned)time(0));
		for (int j = 0; j < S_num[i];j++) {
			//产生变异维度
			DimensionRand(dim_num, set_num2);
			for (int q = 0; q < dim_num; q++) {
				if (q >= set_num2)
					set_rand[q] = -1;
			}
			for (int k = 0; k < set_num2;k++) {
				spark[i][j][set_rand[k]] = spark[i][j][set_rand[k]] * GaussianRand(1, 1);
				Mapping(spark,i,j, set_rand[k]);//映射
			}
		}
	}
}

3.5 选择策略
烟花算法初探_第13张图片
选择策略的作用是产生新一代个体,引论中选择轮盘赌算法进行选择。在这里偷个懒,使用精英保留策略产生子代,即从烟花和火花中选择最好的个体烟花或者火花成为子代。
实现过程如下:

void Select() {
	double fit_tem1[fire_num];
	int fit_index_tem1[fire_num];
	double fit_tem2[fire_num][fire_all];
	int fit_index_tem2[fire_num][fire_all];
	//初始化
	for (int i = 0; i < fire_num;i++) {
		fit_tem1[i] = -1;
		fit_index_tem1[i] = i;
		for (int j = 0; j < fire_all;j++) {
			fit_tem2[i][j] = -1;
			fit_index_tem2[i][j] = j;
		}
	}
	//计算适应值
	for (int i = 0; i < fire_num;i++) {
		fit_tem1[i] = Fitness(x_loc,i);
		for (int j = 0; j < S_num[i];j++) {
			fit_tem2[i][j] = Fitness(spark[i],j);
		}
	}
	//适应值排序:由小到大->冒泡排序
	for (int i = 1; i < fire_num; i++) {
		for (int j = 0; j < fire_num - i; j++) {
			if (fit_tem1[j + 1] < fit_tem1[j]) {
				double compare_tem = fit_tem1[j];
				int count_tem = fit_index_tem1[j];
				fit_tem1[j] = fit_tem1[j + 1];
				fit_index_tem1[j] = fit_index_tem1[j+1];
				fit_tem1[j + 1] = compare_tem;
				fit_index_tem1[j + 1] = count_tem;
			}
		}
	}
	for (int i = 0; i < fire_num;i++) {
		for (int k = 1; k < S_num[i]; k++) {
			for (int j = 0; j < S_num[i] - k; j++) {
				if (fit_tem2[i][j] != -1) {
					if (fit_tem2[i][j + 1] < fit_tem2[i][j]) {
						double compare_tem = fit_tem2[i][j];
						int count_tem = fit_index_tem2[i][j];
						fit_tem2[i][j] = fit_tem2[i][j + 1];
						fit_index_tem2[i][j] = fit_index_tem2[i][j + 1];
						fit_tem2[i][j + 1] = compare_tem;
						fit_index_tem2[i][j + 1] = count_tem;
					}
				}
			}
		}
	}
	for (int i = 0; i < fire_num;i++) {
		int index_select = -1;
		double fit_select = fit_tem1[i];
		if (fit_select > fit_tem2[i][0]) {
			fit_select = fit_tem2[i][0];
			index_select = fit_index_tem2[i][0];
		}
		for (int k = 0; k < dim_num; k++) {
			if (fit_select != fit_tem1[i]) {
				x_loc[i][k] = spark[i][index_select][k];
			}			
		}
	}
}

经测试,对应问题结果无限趋近于最优值。

结语:引论中提供了大量的函数测试集,便于对算法进行测试。
此外,烟花算法提出时间较短,还存在大量的研究缺口以及改进措施,引论中也有相应描述。

你可能感兴趣的:(智能算法学习)