前沿:函数优化求解问题学习过程中,不可避免选择求解算法,且不同的算法收敛速度不同,复杂度不同。探究问题求解的性能,则需要对求解算法进行对比。因此,在这里,引入烟花算法。
以下资料来源于书籍:《烟花算法引论》谭营 著;科学出版社,2015
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]);
}
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 映射规则
产生的火花以及子代难免出现超出界限的情况,这时需要对界限进行操作;一种方法是:若位置超出界限,则重新随机生成;另一种方法是:若位置超出界限,则将其映射到界限以内。烟花算法则使用第二种方法。
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;
}
}
}
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 选择策略
选择策略的作用是产生新一代个体,引论中选择轮盘赌算法进行选择。在这里偷个懒,使用精英保留策略产生子代,即从烟花和火花中选择最好的个体烟花或者火花成为子代。
实现过程如下:
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];
}
}
}
}
经测试,对应问题结果无限趋近于最优值。
结语:引论中提供了大量的函数测试集,便于对算法进行测试。
此外,烟花算法提出时间较短,还存在大量的研究缺口以及改进措施,引论中也有相应描述。