遺傳演算法是解決搜尋問題的一種通用演算法。
模擬自然界優勝劣汰的進化現象,把搜尋問題轉化為遺傳問題,把可能的解轉為成一個向量——染色體,向量的每個元素稱為基因。通過不斷計算各染色體的適應值,選擇最好的染色體,獲得最優解。
基本概念 (以下均以二進位制串 a=<1000101110110101000111> 為例)
1. 遺傳:子代和父代具有相同或相似的性狀,保證物種的穩定性;
2. 變異:子代與父代,子代不同個體之間總有差異,是生命多樣性的根源;
3. 生存鬥爭和適者生存:具有適應性變異的個體被保留,不具適應性變異的個體被淘汰。
自然選擇過程是長期的、緩慢的、連續的過程。
4. 個體與種群
● 個體就是模擬生物個體而對問題中的物件(一般就是問題的解)的一種稱呼,一個個體也就是搜尋空間中的一個點。
● 種群就是模擬生物種群而由若干個體組成的群體, 它一般是整個搜尋空間的一個很小的子集。
5. 適應度與適應度函式
● 適應度就是借鑑生物個體對環境的適應程度,而對問題中的個體物件所設計的表徵其優劣的一種測度。
● 適應度函式就是問題中的全體個體與其適應度之間的一個對應關係。它一般是一個實值函式。該函式就是遺傳演算法中指導搜尋的評價函式,數值越接近目標值則說明適應度越高。
6. 染色體與基因
● 染色體(chromosome)就是問題中個體的某種字串形式的編碼表示。字串中的字元也就稱為基因。
7. 遺傳操作
亦稱遺傳運算元(genetic operator),就是關於染色體的運算。遺傳演算法中有三種遺傳操作:
● 選擇 (selection)
● 交叉(crossover,亦稱交換、交配或雜交)
● 變異(mutation,亦稱突變)
現在寫個簡單的例子:設 f(x) = -x2 + 2x + 0.5,求 max f(x), x在[-1, 2]之間。
對於二進位制串 a=<1000101110110101000111> ;
1.先將其轉為十進位制數:ve=2288967
2.將其轉化為[-1,2]內的實數為:
X=-1+ve*(2-(-1))/((2^22)-1)=0.631797
3.隨機的產生一個初始群體(這裡假設初始群體的個體數為 4)
pop1={
<1101011101001100011110>, % a1
<1000011001010001000010>, % a2
<0001100111010110000000>, % a3
<0110101001101110010101>} % a4
4.轉化成 [-1, 2] 之間的十進位制數即為
pop1={ 1.523032,0.574022,-0.697235,0.247238}
5.定義適應函式和求適應值
由於目標函式 f(x) 在 [-1, 2] 內的值有正有負,所以必須通過建立適應函式與目標函式的對映關係,保證對映後的適應值非負,而且目標函式的優化方向應對應於適應值增大的方向,也為以後計算各個體的入選概率打下基礎。
最後假設得到適應值:
g(pop1)={2.226437,2.318543, 0,1.933350}
6.算出入選下一代的概率:
p(pop1)=g(pop1)/sum(g(pop1))
={0.343675, 0.357892, 0, 0.298433}
7.產生種群
newpop1={
<110101110 1001100011110>, % a1
<100001100 1010001000010>, % a2
<10000110010100 01000010>, % a2
<01101010011011 10010101>} % a4
8.交叉:
將第七步的加粗部分交換,(a1與a2,a3與a4)得到如下結果:
<1101011101010001000010>, % a1
<1000011001001100011110>, % a2
<10000110 0 1010010010101>, % a2
<0110101001101101000010>} % a4
9.變異:將a3中加粗基因變異:
<1101011101010001000010>, % a1
<1000011001001100011110>, % a2
<10000110 1 1010010010101>, % a2
<0110101001101101000010>} % a4
10.終止:我們可以採用遺傳指定代數的方法進行停止程式的執行,但是精確度較低,亦可以根據個體的差異來判斷,通過計算種群中基因多樣性測度,即所有基因位相似程度來進行控制
來一個實際的例子加程式碼(本人也正在學習java,如有不足之處歡迎指出)
用遺傳演算法( GA )求如下問題的最優解, x1, x2精確到小數點後2位。 (採用二進位制編碼方法)
max f (x1, x2) = 2x1·sin(8p x2) +x2·cos(13p x1)
x1:[-3,7]
x2:[-4,10]
程式碼如下:
class chromasome{//染色體
public static final int DNAsize1=10;
public static final int DNAsize2=11;
int []DNA1=new int[DNAsize1];
int []DNA2=new int[DNAsize2];
chromasome(){
int a,b;
for(int i=0;i<DNAsize1;i++){
a=(int)(0+Math.random()*(1-0+1));
DNA1[i]=a;
}
for(int i=0;i<DNAsize2;i++){
b=(int)(0+Math.random()*(1-0+1));
DNA2[i]=b;
}
}
double twoToten1(){
String a ;
a=moeth.velueTostr(this.DNA1);
int d = Integer.parseInt(a, 2); // 2進位制
double b=Math.pow(2, this.DNAsize1);
return -3+(d*(7+3)/(b-1));
}
double twoToten2(){
String a ;
a=moeth.velueTostr(this.DNA2);
int d = Integer.parseInt(a, 2); // 2進位制
double b=Math.pow(2, this.DNAsize2);
return -4+(d*(10+4)/(b-1));
}
void variation(){//變異函式
}
void getChromasome(){//輸出看看染色體
System.out.println("-------------------");
for(int i=0;i<this.DNAsize1;i++){
System.out.print(this.DNA1[i]);
}
System.out.println();
for(int i=0;i<this.DNAsize2;i++){
System.out.print(this.DNA2[i]);
}
System.out.println();
System.out.println(this.adapt()-20);
}
double adapt(){//求適應值
//2x1·sin(8p x2) +x2·cos(13p x1)
double x1=this.twoToten1();
//System.out.println("x1="+x1);
double x2=this.twoToten2();
//System.out.println("x2="+x2);
double value=2*x1*Math.sin(8*Math.PI*x2)+x2*Math.cos(13*Math.PI*x1);
//System.out.println("value="+value);
return value+20;
}
}
public class genetic {
/**
* @param args
*/
int TEXT=1;//除錯用的
static final int DNAnum=220;
chromasome[] DNAarr=new chromasome[DNAnum];
double []adapt_arr=new double[DNAnum];
double []select_rate=new double [DNAnum];
static final double copulationRate=0.5;//交配概率
static final double variationRate=0.01;//變異概率
static int generationNum=0;//遺傳代數
genetic(){
this.initDNA();
if(TEXT==1){
}
}
//--------------------------------------------------------------------------
void TEXToutput(){
for(int i=0;i<DNAnum;i++){
DNAarr[i].getChromasome();
}
System.out.println();
}
//--------------------------------------------------------------------------
void initDNA(){//隨機生成多條染色體
for(int i=0;i<DNAnum;i++){
DNAarr[i]=new chromasome();
}
}
void formDNA(){
int a=this.DNAnum/6;
DNAarr[DNAnum-1]=DNAarr[0];
//DNAarr[DNAnum-3]=DNAarr[0];
//DNAarr[DNAnum-5]=DNAarr[0];
//DNAarr[DNAnum-7]=DNAarr[0];
//DNAarr[DNAnum-2]=DNAarr[1];
//DNAarr[DNAnum-4]=DNAarr[1];
// for(int i=0;i<a;i++){
// DNAarr[DNAnum-i-1]=DNAarr[i];
// }
//DNAarr[DNAnum-2]=DNAarr[0];
//DNAarr[DNAnum-3]=DNAarr[0];
//DNAarr[DNAnum-4]=DNAarr[1];
}
// int chance(){//計算概率
// return 1;
// }
void select(){
double num=0;
for(int i=0;i<this.DNAnum;i++){
//System.out.println("------------------------"+i+1+"---------------");
//DNAarr[i].getChromasome();
adapt_arr[i]=DNAarr[i].adapt();
num+=adapt_arr[i];
//System.out.println("-----------------------------------------------");
}
for(int i=0;i<this.DNAnum;i++){
select_rate[i]=adapt_arr[i]/num;
//System.out.println("------------------------"+i+1+"---------------");
//System.out.println("select_rate="+select_rate[i]);
//System.out.println("----------------------------------------------");
}
}
void paixu(){
for(int i=1;i<select_rate.length;i++){
double m=select_rate[i];
chromasome n=DNAarr[i];
int k=i;
for(int j=i-1;j>=0&&select_rate[j]<m;j--){
select_rate[j+1]=select_rate[j];
DNAarr[j+1]=DNAarr[j];
k--;
}
select_rate[k]=m;
DNAarr[k]=n;
}
}
void copulation(){//交配函式
int a;
for(int j=1;j<DNAnum;j++){
a=(int)(1+Math.random()*(DNAarr[0].DNAsize1-1-1+1));
for(int i=a;i<DNAarr[j].DNAsize1;i++){
int b=DNAarr[j-1].DNA1[i];
this.DNAarr[j-1].DNA1[i]=DNAarr[j].DNA1[i];
this.DNAarr[j].DNA1[i]=b;
}
j++;
}
for(int j=1;j<DNAnum;j++){
a=(int)(1+Math.random()*(DNAarr[0].DNAsize2-1-1+1));
for(int i=a;i<DNAarr[j].DNAsize2;i++){
int l=DNAarr[j-1].DNA2[i];
this.DNAarr[j-1].DNA2[i]=DNAarr[j].DNA2[i];
this.DNAarr[j].DNA2[i]=l;
}
j++;
}
}
void getDNA(){
for(int i=0;i<DNAnum;i++){
DNAarr[i].getChromasome();
}
}
void variation(){
//int m=(int)(1+Math.random()*(5-1+1));
//System.out.println(m);
int m=3;
while(m--!=0){
for(int a=0;a<DNAnum;a++){
int b=a;
int a_1=(int)(0+Math.random()*(DNAarr[0].DNAsize1-1-0+1));
//int b=(int)(0+Math.random()*(DNAnum-1-0+1));
int b_1=(int)(0+Math.random()*(DNAarr[0].DNAsize2-1-0+1));
//System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$"+"a="+a+"b="+b+"a_1="+a_1+"b_1="+b_1);
if(DNAarr[a].DNA1[a_1]==1){
DNAarr[a].DNA1[a_1]=0;
}else{
DNAarr[a].DNA1[a_1]=1;
}
if(DNAarr[b].DNA2[b_1]==1){
DNAarr[b].DNA2[b_1]=0;
}else{
DNAarr[b].DNA2[b_1]=1;
}
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int nn=20 ;
while(nn--!=0){
int m=200;
genetic g=new genetic();
g.select();
g.paixu();
int oo=0;
while(m--!=0){
//System.out.println("##################################");
//g.getDNA();
//g.select();
g.copulation();
//System.out.println("--------------------交配-------------------");
//g.getDNA();
g.variation();
//System.out.println("-------------------變異------------------");
//g.getDNA();
g.select();
//System.out.println("--------------------選擇-------------------");
//g.getDNA();
g.paixu();
//System.out.println("-------------------形成-------------------");
g.formDNA();
//g.select();
//g.getDNA();
}
//g.getDNA();
//System.out.println(g.DNAarr[0].twoToten1());
//System.out.println(g.DNAarr[0].twoToten2());
System.out.println(g.DNAarr[0].adapt()-20);
}
}
}
結果: