遗传算法的一个例子(C/C++)
作者:newsuppy
摘要: m个工件分配给m架机床的效益最优化问题,使用一种遗传算法解决。
一,已知效益矩阵E
eij | M1 | M2 | M3 | M4 | M5 |
J1 | 5 | 6 | 4 | 8 | 3 |
J2 | 6 | 4 | 9 | 8 | 5 |
J3 | 4 | 3 | 2 | 5 | 4 |
J4 | 7 | 2 | 4 | 5 | 3 |
J5 | 3 | 6 | 4 | 5 | 5 |
Jn为工件,Mn为机床,矩阵对应的一格即为,某工件分配给某机床的效益。效益指花费的时间,金钱等,数值越大越差。产生一个分配序列C=(5,2,3,4,1)指将5号工件分配给1号机床,2号工件分配给2号机床,以此类推求得当前分配对应的效益为3+4+2+5+3=17。最佳化问题就是要求该效益值最小时对应的分配序列。下面采用一种遗传算法,具体算法这里不再复述,可以参考[1]或其他相关书籍。要注意由于工件与机床是一一对应的,算法与一些常见的遗传算法在某些细节上有所不同,如染色体编码,到位,变异。
下面是算法实现,由于某些原因,不得不采用C/C++混合编码,C++代码主要在文件输入输出部分。另外要让程序正常运行需要包括几个支持文件(与程序在同一路径):
benefit.txt输入效益矩阵
num_of_gen.txt最后产生的代序
numofcolony.txt为群体中个体总数
numoftm.txt为工件数与机床数
内容可以如下:
benefit.txt |
5 6 4 8 3 6 4 9 8 5 4 3 2 5 4 7 2 4 5 3 3 6 4 5 5 |
num_of_gen.txt |
50 |
numofcolony.txt |
10 |
numoftm.txt |
5 5 |
注意:由于程序写得比较仓促,未考虑错误处理,请保证相关文件的正确性。
#include <iostream> #include <fstream> #include <algorithm> #include <numeric> #include <stdlib.h> #include <time.h> #include <math.h> using namespace std;
void generate_colony(int **colony, int num_of_chromosomes, int num_of_job); //初始群体产生 int compute_benefit(int **benefit_matrix, int *chromosome, int num_of_machine); // 对单个染色体的效益评估 void copy_chromosomes(int **colony, int num_of_chromosomes, int num_of_job, int *benefit_array);//复制 int execute_probably(float probability); //按一定概率返回1或0 //上面的函数实现中使用rand产生随机数,这是不严格的,应该采用一个均匀(Uniform)分布的随机数生成器
void exchange_gene(int *chromosome_first, int *chromosome_second, int num_of_job); //对两个染色体实行交换 void reverse_gene(int *chromosome, int num_of_job); //对单个染色体实行到位 void gene_mutate(int *chromosome, int num_of_job); //对单个染色体实行变异
void ERV_colony(int **colony, float pe, float pr, float pv, int num_of_job, int num_of_chromosomes); //对群体按概率实行交换,到位和变异
int main() { int **benefit_matrix = NULL; // 效益矩阵 int num_of_job; // 工件数 int num_of_machine; // 机床数
ifstream inputTM("numoftm.txt"); inputTM >> num_of_job >> num_of_machine; inputTM.close();
benefit_matrix = (int**)malloc(sizeof(int*)*num_of_job); for (int i=0; i<num_of_job; ++i) { benefit_matrix[i] = (int*)malloc(sizeof(int)*num_of_machine); }
ifstream inputBenefit("benefit.txt"); for (int i=0; i<num_of_job; ++i) { for (int j=0; j<num_of_machine; ++j) { inputBenefit >> benefit_matrix[i][j]; } } inputBenefit.close();
/********************************************* // Test for inital data's input cout <<num_of_job << '/t' << num_of_machine << endl; for (int i=0; i<num_of_job; ++i) { for (int j=0; j<num_of_machine; ++j) { cout << benefit_matrix[i][j] << '/t'; } cout << '/n'; } **********************************************/
int num_of_chromosomes; //群体数 ifstream inputCln("numofcolony.txt"); inputCln >> num_of_chromosomes; inputCln.close();
int **colony = NULL; //群体 colony = (int**)malloc(sizeof(int*)*num_of_chromosomes); for (int i=0; i<num_of_chromosomes; ++i) { colony[i] =(int*)malloc(sizeof(int)*num_of_job); }
srand(time(0)); generate_colony(colony, num_of_chromosomes, num_of_job);
cout << "Origin Colonies" << '/n'; /***********************************/ // Test for genetare_colony for (int i=0; i<num_of_chromosomes; ++i) { for (int j=0; j<num_of_job; ++j) { cout << colony[i][j] << '/t'; }
cout << '/n'; } /************************************/
int *benefit_array = NULL; // 群体中每个个体的效益组成的数组 benefit_array = (int*)malloc(sizeof(int)*num_of_chromosomes); for (int i=0; i<num_of_chromosomes; ++i) { benefit_array[i] = compute_benefit(benefit_matrix, colony[i], num_of_machine); }
cout << "Current benefit" << '/n' << "mean:" << (float)accumulate(benefit_array, benefit_array+num_of_chromosomes, 0) / num_of_chromosomes << '/t' << "max:" << *max_element(benefit_array, benefit_array+num_of_chromosomes) << '/t' << "min:" << *min_element(benefit_array, benefit_array+num_of_chromosomes) << '/n';
int num_of_gen; // 产生的代数,也就是最后产生的那个代的序数 ifstream inputNG("num_of_gen.txt"); inputNG >> num_of_gen; inputNG.close();
float probability_of_exchange = 0.7f ; float probability_of_reverse = 0.2f ; float probability_of_mutate = 0.01f ;
for (int i=0; i<num_of_gen; ++i) { //调用复制子程序 copy_chromosomes(colony, num_of_chromosomes, num_of_job, benefit_array);
ERV_colony(colony, probability_of_exchange, probability_of_reverse, probability_of_mutate, num_of_job, num_of_chromosomes);
//重新计算各个个体的效益 for (int j=0; j<num_of_chromosomes; ++j) { benefit_array[j] = compute_benefit(benefit_matrix, colony[j], num_of_machine); }
//本代评估效益 cout << "current gen : " << i+1 << '/n' << "mean: " << (float)accumulate(benefit_array, benefit_array+num_of_chromosomes, 0) / num_of_chromosomes << '/t' << "max:" << *max_element(benefit_array, benefit_array+num_of_chromosomes) << '/t' << "min:" << *min_element(benefit_array, benefit_array+num_of_chromosomes) << '/n'; }
cout << "Laster Colony" << '/n'; for (int i=0; i<num_of_chromosomes; ++i) { for (int j=0; j<num_of_job; ++j) { cout << colony[i][j] << '/t'; }
cout << '/n'; }
// free all resource for (int i=0; i<num_of_job; ++i) { free(benefit_matrix[i]); } free(benefit_matrix);
for (int i=0; i<num_of_chromosomes; ++i) { free(colony[i]); } free(colony);
free(benefit_array);
system("pause"); }
void generate_colony(int **colony, int num_of_chromosomes, int num_of_job) { int *initial_array = (int*)malloc(sizeof(int)*num_of_job); for (int i=0; i<num_of_job; ++i) { initial_array[i] = i + 1; }
for (int i=0; i<num_of_chromosomes; ++i) { random_shuffle(initial_array, initial_array+num_of_job); copy(initial_array, initial_array+num_of_job, colony[i]); }
free(initial_array); }
int compute_benefit(int **benefit_matrix, int *chromosome, int num_of_machine) { int benefit = 0; for (int i=0; i<num_of_machine; ++i) { benefit += benefit_matrix[chromosome[i]-1][i]; }
return benefit; }
void copy_chromosomes(int **colony, int num_of_chromosomes, int num_of_job, int *benefit_array) { int i, j; int *next_gen_reserve; //各个个体在后代中的复制量 int hasCopyed = 0; // 防止复制数超过群体总数ֺ int **temp_colony; //暂存群体 float mean, max_benefit, min_benefit; float big_separator, small_separator;
mean = (float)accumulate(benefit_array, benefit_array+num_of_chromosomes, 0) / (float)num_of_chromosomes; max_benefit = *max_element(benefit_array, benefit_array+num_of_chromosomes); min_benefit = *min_element(benefit_array, benefit_array+num_of_chromosomes); big_separator = max_benefit - (max_benefit-mean) / 2; small_separator = min_benefit + (mean-min_benefit) / 2;
temp_colony = (int**)malloc(sizeof(int*)*num_of_chromosomes); for (i=0; i<num_of_chromosomes; ++i) { temp_colony[i] =(int*)malloc(sizeof(int)*num_of_job); }
// 复制暂存群体 for (i=0; i<num_of_chromosomes; ++i) { for (j=0; j<num_of_job; ++j) { temp_colony[i][j] = colony[i][j]; } }
next_gen_reserve = (int*)malloc(sizeof(int)*num_of_chromosomes);
// 计算个体贡献并进行参数圆整 for (i=0; i<num_of_chromosomes; ++i) { if (benefit_array[i] >= big_separator) next_gen_reserve[i] = 0; else if (benefit_array[i] <= small_separator) next_gen_reserve[i] = 2; else next_gen_reserve[i] = 1; }
for (i=0; i<num_of_chromosomes; ++i) { for (j=0; j<next_gen_reserve[i]; ++j) { if (hasCopyed >= num_of_chromosomes) { i = num_of_chromosomes; break; } memcpy(colony[hasCopyed], temp_colony[i], sizeof(colony[0][0])*num_of_job); ++hasCopyed; } }
for (i=0; i<num_of_chromosomes; ++i) { free(temp_colony[i]); } free(temp_colony); free(next_gen_reserve); }
int execute_probably(float probability) { if (probability > 1.0) return 1; else if (probability <= 0.0) return 0; else { int rndNum = rand() % 1000;
if (rndNum < (int)(probability * 1000.0)) return 1; else return 0; } }
void exchange_gene(int *chromosome_first, int *chromosome_second, int num_of_job) { int exchange_pos; //交换随机点 int *derived_first, *derived_second; //交换后的两个新子代的临时存放 int i, j, k; int is_equal;
exchange_pos = rand() % num_of_job;
derived_first = (int*)malloc(sizeof(int)*num_of_job); derived_second = (int*)malloc(sizeof(int)*num_of_job);
// 复制交换点前的基因 memcpy(derived_first, chromosome_first, sizeof(int)*(1+exchange_pos)); memcpy(derived_second, chromosome_second, sizeof(int)*(1+exchange_pos));
// 由两个亲本产生第一个子代 k = exchange_pos + 1; for (i=0; i<num_of_job; ++i) { is_equal = 0;
for (j=0; j<=exchange_pos; ++j) { if (chromosome_second[i]==chromosome_first[j]) { is_equal = 1; break; } }
if (is_equal == 0) { derived_first[k] = chromosome_second[i]; ++k; } }
// 由两个亲本产生第二个子代 k = exchange_pos + 1; for (i=0; i<num_of_job; ++i) { is_equal = 0;
for (j=0; j<=exchange_pos; ++j) { if (chromosome_first[i]==chromosome_second[j]) { is_equal = 1; break; } }
if (is_equal == 0) { derived_second[k] = chromosome_first[i]; ++k; } }
// 覆盖原始亲本 memcpy(chromosome_first, derived_first, sizeof(int)*num_of_job); memcpy(chromosome_second, derived_second, sizeof(int)*num_of_job);
free(derived_first); free(derived_second); }
void reverse_gene(int *chromosome, int num_of_job) { int first_rev_pos; //第一倒位点 int second_rev_pos; //第二倒位点 int i, distance; int temp;
first_rev_pos = rand() % num_of_job; second_rev_pos = rand() % (num_of_job-first_rev_pos)+first_rev_pos;
distance = (second_rev_pos - first_rev_pos) / 2; for (i=0; i<=distance; ++i) { temp = chromosome[first_rev_pos+i]; chromosome[first_rev_pos+i] = chromosome[second_rev_pos-i]; chromosome[second_rev_pos-i] = temp; } }
void gene_mutate(int *chromosome, int num_of_job) { int mutate_pos; // 变异点 int mutate_value; // 变异后基因值 int ex_pos; //与变异点的交换点 int i;
mutate_pos = rand() % num_of_job; mutate_value = rand() % num_of_job + 1;
for (i=0; i<num_of_job; ++i) { if (chromosome[i] == mutate_value) { ex_pos = i; break; } }
i = chromosome[ex_pos]; chromosome[ex_pos] = chromosome[mutate_pos]; chromosome[mutate_pos] = i; }
void ERV_colony(int **colony, float pe, float pr, float pv, int num_of_job, int num_of_chromosomes) { int **tmp_colony; int i; int first, second;
tmp_colony = (int**)malloc(sizeof(int*)*num_of_chromosomes); for (i=0; i<num_of_chromosomes; ++i) { tmp_colony[i] =(int*)malloc(sizeof(int)*num_of_job); }
// copy for (i=0; i<num_of_chromosomes; ++i) { memcpy(tmp_colony[i], colony[i], sizeof(int)*num_of_job); }
for (i=0; i<num_of_chromosomes; i+=2) { first = rand() % num_of_chromosomes; while (1) { second = rand() % num_of_chromosomes; if (first != second) break; }
memcpy(colony[i], tmp_colony[first], sizeof(int)*num_of_job); memcpy(colony[i+1], tmp_colony[second], sizeof(int)*num_of_job);
if (execute_probably(pe)) exchange_gene(colony[i],colony[i+1],num_of_job);
if (execute_probably(pr)) { reverse_gene(colony[i], num_of_job); reverse_gene(colony[i+1], num_of_job); }
if (execute_probably(pv)) { gene_mutate(colony[i], num_of_job); gene_mutate(colony[i+1], num_of_job); } }
// free all resource for (int i=0; i<num_of_chromosomes; ++i) { free(tmp_colony[i]); } free(tmp_colony); }
|
下面是程序编译运行后的一种结果(已经在VC7.1,Dev-C++ 4.9.8 .0上编译测试过)。输出为初始群体,0至第50代的平均效益(mean)
最差效益(max),最佳效益(min)。最后是最后一代群体的分配情况。
由于初始序列随机产生,且一般遗传算法往往存在难于收敛到最佳解的情况,本程序有时候也会无法收敛到最佳解。但是只要多运行几次,就可以获得最佳解序列。
最佳分配序列:5 2 3 4 1, 此时效益为17
Origin Colonies 5 3 2 4 1 5 2 1 4 3 2 5 4 1 3 2 3 5 4 1 1 2 4 5 3 1 3 2 4 5 5 4 3 2 1 3 1 4 2 5 5 3 4 1 2 5 1 3 4 2 Current benefit mean:23 max:28 min:18 current gen : 1 mean: 21.8 max:29 min:18 current gen : 2 mean: 19.7 max:23 min:18 current gen : 3 mean: 19.8 max:24 min:17 current gen : 4 mean: 18.4 max:21 min:17 current gen : 5 mean: 18.2 max:21 min:17 current gen : 6 mean: 17.4 max:18 min:17 current gen : 7 mean: 17.8 max:22 min:17 current gen : 8 mean: 17.2 max:18 min:17 current gen : 9 mean: 17 max:17 min:17 current gen : 10 mean: 17.3 max:20 min:17 current gen : 11 mean: 17 max:17 min:17 current gen : 12 mean: 17.3 max:20 min:17 current gen : 13 mean: 18.8 max:27 min:17 current gen : 14 mean: 17.6 max:23 min:17 current gen : 15 mean: 17.5 max:20 min:17 current gen : 16 mean: 18.2 max:23 min:17 current gen : 17 mean: 17.5 max:22 min:17 current gen : 18 mean: 17 max:17 min:17 current gen : 19 mean: 17 max:17 min:17 current gen : 20 mean: 17.5 max:22 min:17 current gen : 21 mean: 17.6 max:20 min:17 current gen : 22 mean: 17 max:17 min:17 current gen : 23 mean: 17.8 max:22 min:17 current gen : 24 mean: 17.6 max:23 min:17 current gen : 25 mean: 17.5 max:22 min:17 current gen : 26 mean: 17 max:17 min:17 current gen : 27 mean: 17 max:17 min:17 current gen : 28 mean: 17 max:17 min:17 current gen : 29 mean: 17 max:17 min:17 current gen : 30 mean: 18.1 max:22 min:17 current gen : 31 mean: 17.8 max:20 min:17 current gen : 32 mean: 17 max:17 min:17 current gen : 33 mean: 17.6 max:23 min:17 current gen : 34 mean: 17.3 max:20 min:17 current gen : 35 mean: 17 max:17 min:17 current gen : 36 mean: 17 max:17 min:17 current gen : 37 mean: 17 max:17 min:17 current gen : 38 mean: 17 max:17 min:17 current gen : 39 mean: 18.1 max:23 min:17 current gen : 40 mean: 17.3 max:20 min:17 current gen : 41 mean: 17 max:17 min:17 current gen : 42 mean: 17 max:17 min:17 current gen : 43 mean: 17 max:17 min:17 current gen : 44 mean: 17.5 max:22 min:17 current gen : 45 mean: 17 max:17 min:17 current gen : 46 mean: 18.3 max:27 min:17 current gen : 47 mean: 17.9 max:20 min:17 current gen : 48 mean: 17 max:17 min:17 current gen : 49 mean: 17 max:17 min:17 current gen : 50 mean: 17 max:17 min:17 Laster Colony 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 5 2 3 4 1 |
参考文献:
[1] 计算机集成制造系统 主编 严新民 西北工业大学出版社 p110-p114