遺傳算法

摘要遺傳算法(geneticalgorithmsGA)是模仿生物遺傳學自然選擇機理,在對隨機自適應的全局搜索算法Holland霍蘭德)及自然界的“自然選擇”和“優勝劣汰”Darwin達爾文)和生物遺傳學說( Gregor Johann Mendel格里果·約翰·孟德爾)的理論進行綜合,通過人工方式所構造的一類隨機自適應全局優化搜索算法,是對生物進化過程進行的一種數學仿真,是進化計算的最重要的形式。遺傳算法爲那些難以找到傳統數學模型的難題指出了一個解決方法。進化計算和遺傳算法借鑑了生物科學中的某些知識,這也體現了人工智能這一交叉學科的特點。本文主要論述計算機科學與技術專業大三下專業課《人工智能》第六個實驗算法。

關鍵字:人工智能,遺傳算法,進化計算

Production system

Abstract: Genetic algorithm (geneticalgorithms, GA) is mimic biological genetics and natural selection mechanism, the random global search algorithm of adaptive (Holland, Mr Rand) and the nature of "natural selection" and "evolution" Darwin (Charles Darwin) and biological genetic theory (Gregor Johann Mendel in fruit, John Mendel) theory synthetically, through artificial means the constructed a kind of random adaptive global optimization search algorithm, is a kind of mathematical simulation of biological evolution process, is the most important form of evolutionary computation. Genetic algorithm (ga) for those who are hard to find the problem of traditional mathematical model points out a solution. Evolutionary computation and genetic algorithm is used to refer to some knowledge of the biological sciences, this also reflected the characteristics of artificial intelligence in the interdisciplinary. This paper mainly discusses the computer science and technology under the junior in professional class "artificial intelligence" sixth experiment algorithm.

Keywords: Artificial intelligence, genetic algorithms, evolutionary computation

1,編碼與譯碼

  進化計算求解問題的第一步是對問題的可能解進行編碼,目的是爲了有效地執行遺傳操作。編碼是一個從問題的解空間到編碼空間的映射。如許多應用問題結構很複雜,但可以化爲簡單的位串形式編碼表示,變換爲位串形式編碼表示的過程叫編碼;將問題結構而相反將位串形式編碼表示變換爲原問題結構的過程叫譯碼。

 借用生物的術語,把位串形式的解的編碼表示叫染色體基因型(基因表達),或叫個體原問題結構即一個染色體解碼後所對應的解稱爲表現型編碼空間也稱爲基因型空間或搜索空間。解空間也稱爲表現型空間。

    進化算法不是直接作用在問題的解空間上,而是交替地作用在編碼空間和解空間上。編碼空間對個體進行遺傳操作,在解空間對問題的解進行評估
圖片         


2,適應度函數

爲了體現染色體的適應能力,引入了對問題中的每一個染色體都能進行度量的函數,叫適應度函數。通過適應度函數來決定染色體的優、劣程度,它體現了自然進化中的優勝劣汰原則。對優化問題,適應度函數就是目標函數。TSP的目標是路徑總長度爲最短,路徑總長度的倒數就可以爲TSP的適應度函數。
    
其中wn+1= w1。適應度函數要有效反映每一個染色體與問題的最優解染色體之間的差距,一個染色體與問題的最優解染色體之間的差距小,則對應的適應度函數值之差就小,否則就大。適應度函數的取值大小與求解問題對象的意義有很大的關係。 

圖片

3,遺傳操作

    簡單遺傳算法的遺傳操作主要有三種:選擇(selection)、交叉(crossover)、變異(mutation)改進的遺傳算法大量擴充了遺傳操作,以達到更高的效率。

    選擇操作也叫複製操作,根據個體的適應度函數值所度量的優、劣程度決定它在下一代是被淘汰還是被遺傳。一般地說,選擇將使適應度較大(優良)個體有較大的存在機會,而適應度較小(低劣)的個體繼續存在的機會也較小。

    1)計算各染色體適應度值

    2)累計所有染色體適應度值(或選擇概率),記錄每個個體的適應度累加值(或概率累加值)

    3) 產生一個隨機數 r0< r < sumN(0< r < 1

    4)若sumk-1< r £ sumk(qk-1< r £ qk ,則選擇第k個個體進入交配池。
 
5) 重複(3)和(4),直到獲得足夠的染色體。  
 

4,程序流程
 

    
一般遺傳算法的主要步驟如下:

(1) 隨機產生一個由確定長度的特徵字符串組成的初始羣體。

(2) 對該字符串羣體迭代的執行下面的步①和② ,直到滿足停止標準:

①計算羣體中每個個體字符串的適應值;

②應用選擇、交叉和變異等遺傳算子產生下一代羣體。

      (3) 把在後代中出現的最好的個體字符串指定爲遺傳算法的執行結果,這個結果可以表示問題的一個解。 

        圖片


5,問題解析


圖片 


圖片

圖片 
圖片

圖片

圖片


6,程序設計

圖片 


#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<iomanip>
using namespace std;

const int NUM=1000;       //最大迭代次數
const int POP_SIZE=50;   //種羣規模:個體數量
const int GENE=33;       //每個個體染色體個數
const int GB1=18;        //染色體手段基因片段(二進制)
const int GB2=15;        //染色體末端基因片段(二進制)
const int GD=6;          //十進制保留小數點位數
const double PI=3.1415926;

void initialize(int v[][GENE])   //初始化羣體
{
	int ii,ij;
	srand(time(0));
	cout<<"基因初始化:"<<endl;
	for(ii=0;ii<POP_SIZE;ii++)
	{	
		cout<<endl<<"個體"<<setw(2)<<ii+1<<"基因型 ";
		for(ij=0;ij<GENE;ij++)
		{
			v[ii][ij]=2*rand()/RAND_MAX;
			cout<<v[ii][ij];
		}
	}
	cout<<endl;
}

void evaluation(int v[][GENE],double eval[]) //評估函數
{	
	int ii,ij;
	double x1,x2;
	for(ii=0;ii<POP_SIZE;ii++)
	{	
		x1=x2=0;             
		for(ij=0;ij<GB1;ij++)   //二進制片段轉爲十進制編碼
		{
			x1+=v[ii][ij]*pow(2,(GB1-(ij+1)));
		}
		for(ij=GB1;ij<GENE;ij++)
		{
			x2+=v[ii][ij]*pow(2,(GENE-(ij+1)));
		}
		x1=-3.0+x1*(12.1-(-3.0))/(pow(2,GB1)-1);   //十進制編碼轉爲十進制值
		x2=4.1+x2*(5.8-4.1)/(pow(2,GB2)-1);
		eval[ii]=21.5+x1*sin(4*PI*x1)+x2*sin(20*PI*x2);
	}
}

int best_eval(double eval[])   //找出每代中最優秀個體基因值
{	
	int ii,cursor=0;
	for(ii=0;ii<POP_SIZE;ii++)
	{	
		if(eval[ii]>eval[cursor])
		{
			cursor=ii;
		}
	}
	return cursor;
}

int worst_eval(double eval[])   //找出每代中最差個體基因值
{	
	int ii,cursor=0;
	for(ii=0;ii<POP_SIZE;ii++)
	{	
		if(eval[ii]<eval[cursor])
		{
			cursor=ii;
		}
	}
	return cursor;
}

void selection(double eval[],int v[][GENE],int v_next[][GENE])
{	
	int ii,ij,ik;
	double value;
	double p[POP_SIZE];         //選擇概率
	double pp[POP_SIZE]={0};     //累積概率
	double total_value=0;
	for(ii=0;ii<POP_SIZE;ii++)
	{
		total_value+=eval[ii];
	}
	for(ii=0;ii<POP_SIZE;ii++)
	{
		p[ii]=eval[ii]/total_value;
	}
	pp[0]=p[0];
	for(ii=1;ii<POP_SIZE;ii++)
	{
		pp[ii]=pp[ii-1]+p[ii];
	}
	for(ii=0;ii<POP_SIZE;ii++)      //對於每個次代個體的基因型 
	{	
		value=(double)rand()/RAND_MAX;   //轉動輪盤 
		for(ij=0;ij<POP_SIZE;ij++)       //搜索命中區域 
		{	
			if(value<pp[ij])             //找到後複製、跳出 
			{	
				for(ik=0;ik<GENE;ik++)
				{
					v_next[ii][ik]=v[ij][ik];
				}
				break;
			}
		}
	}
}

void crossover(int v[][GENE])
{	
	int ii,ij,ik;
	double p=0.8,value1;
	int n=0,tmp,value2;
	int cursor[POP_SIZE]={-1};     //被選中的染色體下標
	for(ii=0;ii<POP_SIZE;ii++)     //找被選中的染色體下標
	{	
		value1=(double)rand()/RAND_MAX;
		if(value1<p)
		{
			cursor[n++]=ii;
		}
	}
	for(ii=0;ii<n;ii+=2)              //兩兩配對,進行交叉
	{	
		value2=(int)(GENE-1)*rand()/RAND_MAX+1;
		for(ij=value2;ij<GENE;ij++)
		{	
			tmp=v[cursor[ii]][ij];
			v[cursor[ii]][ij]=v[cursor[ii+1]][ij];
			v[cursor[ii+1]][ij]=tmp;
		}
	}
}

void mutation(int v[][GENE])
{	
	int ii,ij,ik;
	int sum,gene;     //基因變異數目
	double pm=0.01;   //變異概率
	sum=(int)(POP_SIZE*GENE*pm)+1;
	for(ii=0;ii<sum;ii++)
	{	
		gene=(int)(POP_SIZE*GENE)*rand()/RAND_MAX;
		ij=gene/(POP_SIZE*GENE);
		ik=gene%(POP_SIZE*GENE);
		v[ij][ik]=1-v[ij][ik];
	}
}

int main(int argc,char **argv)
{	
	int ii,ij,ik,max=0;
	int v[POP_SIZE][GENE];          //本代羣體基因庫
	int v_next[POP_SIZE][GENE];     //次代羣體基因庫
	double eval[POP_SIZE];                   //本代羣體評估值
	double eval_next[POP_SIZE];              //次代羣體評估值
	int best_cursor;                //本代最優個體適值下標
	int best_next_cursor;           //次代最優個體適值下標
	int worst_next_cursor;          //次代最差個體適值下標
	int best_gene[GENE];            //本代最優個體基因型
	initialize(v);  
	for(ii=0;ii<NUM&&max<50;ii++)
	{	
		evaluation(v,eval);               //本代基因評估
		best_cursor=best_eval(eval);      //本代最優個體
		cout<<endl<<"第"<<setw(3)<<ii+1<<"代最優基因:";
		for(ij=0;ij<GENE;ij++)            //保存本代最優基因
		{
			best_gene[ij]=v[best_cursor][ij];
			cout<<best_gene[ij];
		}
		cout<<" 適值:"<<eval[best_cursor];
		selection(eval,v,v_next);       //選擇    
		crossover(v_next);              //交叉
		mutation(v_next);               //變異
		evaluation(v_next,eval_next);  
		worst_next_cursor=worst_eval(eval_next); 
		for(ij=0;ij<GENE;ij++)
		{
			v_next[worst_next_cursor][ij]=best_gene[ij];
		}
		evaluation(v_next,eval_next);  
		best_next_cursor=best_eval(eval_next); 
		eval[best_cursor]==eval_next[best_next_cursor]?max++:max=0;
		for(ij=0;ij<POP_SIZE;ij++)
		{
			for(ik=0;ik<GENE;ik++)
			{
				v[ij][ik]=v_next[ij][ik];
			}
		}
	}
	cout<<endl<<"最優基因適值爲:"<<eval[best_cursor]<<endl;
	cout<<"迭代次數爲:"<<ii<<endl;
	system("pause");
	return 0;
}
/*
**本題最優值是38.818208

(1)  初始化羣體;
(2)  計算羣體上每個個體的適應度值;
(3)  按由個體適應度值所決定的某個規則選    
       擇將進入下一代的個體;
(4)  按概率Pc進行交叉操作;
(5)  按概率Pm進行突變操作;
(6) 若沒有滿足某種停止條件,則轉第(2)步,  
      否則進入下一步。
(7) 輸出羣體中適應度值最優的染色體作爲問題的
     滿意解或最優解。
*/


發佈了21 篇原創文章 · 獲贊 14 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章