遗传算法解决函数优化问题

一、实验目的

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;
}


 

posted @ 2012-11-02 20:18  朱京辉  阅读(1038)  评论(0编辑  收藏  举报