遺傳算法解決函數優化問題

一、實驗目的

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章