一、实验目的
1.掌握遗传算法的基本原理和步骤。
2. 复习VB、VC的基本概念、基本语法和编程方法,并熟练使用VB或VC编写遗传算法程序。
二、实验内容
1. 上机编写程序,解决以下函数优化问题:
2. 调试程序。
3. 根据实验结果,撰写实验报告。
三、实验原理
遗传算法是一类随机优化算法,但它不是简单的随机比较搜索,而是通过对染色体的评价和对染色体中基因的作用,有效地利用已有信息来指导搜索有希望改善优化质量的状态。
标准遗传算法流程图如下图所示,主要步骤可描述如下:
① 随机产生一组初始个体构成初始种群。
② 计算每一个体的适配值(fitness value,也称为适应度)。适应度值是对染色体(个体)进行评价的一种指标,是GA进行优化所用的主要信息,它与个体的目标值存在一种对应关系。
③ 判断算法收敛准则是否满足,若满足,则输出搜索结果;否则执行以下步骤。
④ 根据适应度值大小以一定方式执行复制操作(也称为选择操作)。
⑤ 按交叉概率pc执行交叉操作。
⑥ 按变异概率pm执行变异操作。
⑦ 返回步骤②。
图1.1 标准遗传算法流程图
代码实现::::::
#include <stdio.h> #include <math.h> #include <stdlib.h> #include<time.h> #define byte unsigned char #define step 200 //步长 #define MAX 50 #define N 10 //随机数个数 #define Pc 0.74 //被选择到下一代的概率,个数=Pc*N,小于N 下一代数=上一代,不用处理 #define Pt 0.25 //交叉的概率,个数=Pt*N 舍,小于N 0~(n2+1)随机数,之后部分开始交叉 #define Pm 0.01 //变异的概率,个数=Pm*N*n2 入,小于N 0~(N*(n2+1))随机数/(n2+1)=个体,0~(N*(n2+1))随机数%(n2+1)=该个体基因位置 #define n2 15//2的15次方,共16位 #define next_t (int)(Pt*N)//交叉个数 #define next_m (int)(Pm*N+1)//变异个数 向后约等于 #define e 0.001//次数限制阈值 /* int N=10; //随机数个数 float Pc=0.74; //被选择到下一代的概率,个数=Pc*N,小于N 下一代数=上一代,不用处理 float Pt=0.25; //交叉的概率,个数=Pt*N 舍,小于N 0~(n2+1)随机数,之后部分开始交叉 float Pm=0.01; //变异的概率,个数=Pm*N*n2 入,小于N 0~(N*(n2+1))随机数/(n2+1)=个体,0~(N*(n2+1))随机数%(n2+1)=该个体基因位置 */ byte bitary[N][n2+1],bitary0[N][n2+1];//二进制 int src1[N]; float ShowType(int a);//表现型 void BinNum(int a);//二进制位数n2 float fit_func(float a);//适应度 void DecToBin (int src,int num);//十进制转二进制 void BinToDec (void);//十进制转二进制 int selectT(float a,float b[10]);//选择交叉个体 int selectM(float a,float b[10]);//选择变异个体 void main(void) { //范围是[-100,100]*************************** int src[N],i=0,j=0,k=0,count=0;//十进制 float show[N];//表现型 float fit[N],sumfit=0;//适应度 float pcopy[N];//优胜劣汰,遗传到下一代的概率fit[i]/总和(fit[i]) float pacc[N];//pcopy[i]累加概率值 float prand[N];//随机产生N个0~1的下一代概率 int iselect;//根据概率选择到的个体序号 int new_select[N];//根据概率选择到的个体 int new_T[next_t],new_M[next_m]; float min,min1; printf("随机数(原始母体),表现型, 适配值\n"); srand( (unsigned)time(NULL) ); for(i=0;i<N;i++) { src[i]=rand()%32768; //rand()%201-100===>-100~100的十进制随机数 随时间递增 show[i]=ShowType(src[i]);//转化成表现型 fit[i]=fit_func(show[i]);//计算各个适配值(适应度) sumfit=sumfit+fit[i]; //种群的适应度总和 printf("%5d, %f, %f\n",src[i],show[i],fit[i]); } printf("\n第%d代适配总值\n%f\n",count,sumfit);//第0代 count++; min=sumfit; printf("\n遗传到下一代的概率\n"); for(i=0;i<N;i++) { pcopy[i]=fit[i]/sumfit; printf("%f, ",pcopy[i]); } // 求选择(被复制)的累加概率,用于轮盘赌产生随机数区域,选择下一代个体 printf("\n遗传到下一代的累加概率\n"); pacc[0]=pcopy[0]; for(i=1;i<N;i++) { pacc[i]=pacc[i-1]+pcopy[i]; printf("%f, ",pacc[i]); } //每个src[N]都随机取其中一个pcopy,取得的值pcopy[i]跟pcopy概率大小有关 //模拟轮盘赌方式选择新一代 printf("\n\n新产生的第%d代,表现型, 适配值\n",count); srand( (unsigned)time(NULL) ); for(i=0;i<N;i++) { prand[i]=(float)( (rand()%101)*0.01 );//0~1的十进制小数 ,精确到0.01 iselect=selectT(prand[i],pacc); new_select[i]=src[iselect];//产生的新一代,十进制 show[i]=ShowType(new_select[i]);//转化成表现型 fit[i]=fit_func(show[i]); DecToBin (new_select[i],i); sumfit=sumfit+fit[i]; //种群的适应度总和 printf(" %d %f %f\n",new_select[i],show[i],fit[i]); } printf("\n第%d代适配总值\n%f\n",count,sumfit);//第1代 min1=sumfit; if (min>sumfit) { min1=min; min=sumfit; } while(fabs(min-min1)>e&&count<MAX) { //从新一代选择个体交叉 printf("\n随机产生交叉个体号 "); srand( (unsigned)time(NULL) ); for(i=0;i<2;i++) //简单起见交叉数设为2 { new_T[i]=rand()%N;//0~10的十进制数 产生的交叉个体 if (i>0)//两个不同个体交叉 while(new_T[i]==new_T[i-1]) new_T[i]=rand()%N; printf("%d, ",new_T[i]); } srand( (unsigned)time(NULL) );//随机产生交叉位置 k=rand()%n2;//0~14的十进制数 printf("\n随机产生交叉位置 %d\n",k); printf("\n原编码\n"); for(j=n2;j>=0;j--) printf("%c",bitary[new_T[0]][j]); printf("\n"); for(j=n2;j>=0;j--) printf("%c",bitary[new_T[1]][j]); printf("\n位置%d后交叉编码\n",k); char temp; for(i=k+1;i<n2+1;i++)//交叉 { temp=bitary[new_T[0]][i]; bitary[new_T[0]][i]=bitary[new_T[1]][i]; bitary[new_T[1]][i]=temp; } for(j=n2;j>=0;j--) printf("%c",bitary[new_T[0]][j]); printf("\n"); for(j=n2;j>=0;j--) printf("%c",bitary[new_T[1]][j]); //从新一代选择个体变异 printf("\n随机产生变异个体号 "); srand( (unsigned)time(NULL) ); for(i=0;i<1;i++) //简单起见变异数设为1个 { new_M[i]=rand()%N;//0~9的十进制数 产生的变异个体 k=rand()%(n2+1);//0~15的十进制数 printf("%d\n编码位置 %d\n原编码\n",new_M[i],k); for(j=n2;j>=0;j--) printf("%c",bitary[new_M[i]][j]); if (bitary[new_M[i]][k]=='0')//变异取反 bitary[new_M[i]][k]='1'; else bitary[new_M[i]][k]='0'; printf("\n位置%d变异后编码\n",k); for(j=n2;j>=0;j--) printf("%c",bitary[new_M[i]][j]); } printf("\n"); count++; //新的bitary即产生第二代 printf("\n新产生的第%d代\n",count); for(i=0;i<N;i++) { for(j=n2;j>=0;j--) printf("%c",bitary[i][j]); printf("\n"); } BinToDec ();//二进制转十进制 for(i=0;i<N;i++) { new_select[i]=src1[i]; show[i]=ShowType(src[i]);//转化成表现型 fit[i]=fit_func(show[i]);//计算各个适配值(适应度) sumfit=sumfit+fit[i]; //种群的适应度总和 printf("%5d, %f, %f\n",src1[i],show[i],fit[i]); } printf("\n第%d代适配总值\n%f\n",count,sumfit); if (sumfit<min) { min1=min; min=sumfit; } } printf("\n\n\n*****************\n over \n*****************\n",sumfit); } //////////////////////////子函数//////////////// float ShowType(int a) { float temp; temp=(float)(a*200.0/32767-100);//(2的15次方减1)=32767 return temp; } float fit_func(float a) { float temp; temp=a*a; return temp; } void DecToBin (int src,int num) { int i; //注意负数的补码 if (src<0) { src=(int)pow(2,16)-abs(src); } for (i=0;i<=n2;i++) { bitary[num][i]='0'; bitary0[num][i]='0'; if(src) { bitary[num][i]=(src%2)+48; bitary0[num][i]=(src%2)+48; src=(int)(src/2); } } } void BinToDec (void) { int i,j; for(i=0;i<N;i++) { src1[i]=0; for(j=0;j<n2+1;j++) { src1[i]=src1[i]+(bitary[i][j]-48)*(int)pow(2,j); } } } int selectT(float a,float b[10]) { int i; for(i=0;i<N;i++) { if (a<b[i]) return i; } return -1; }