用程序模擬進化過程:文字進化

圖文應該有關吧,一個幽靈特工(ghost)在異蟲主宰(Overmind)的設計下進化成刀鋒女王(The Queen of Blades)——其實我就是想放Kerrigan而已【手動滑稽】。

進化可以說是生命的本質之一,進化思想也是生命科學的一大基石,但一直以來,進化論都只是通過對大量事實觀察歸納和合理外推得到的理論。筆者認為唯有由物理化學原理和數學推理建立的模型才有可能精確刻畫進化的本質——然而那太過遙遙無期。不過現在我們可以通過一個小程序從感性的層面體驗進化的威力。該程序由visual c++編寫,源文件和可直接運行的程序(advanced edition文件夾下的text.exe,不用安裝VC++)可通過下面的鏈接下載:

百度云:進化模擬小程序

程序的內容是由一段任意長度任意排序的字母進化成你想要的字母序列。比如說我臉滾鍵盤打了個「dkfjskjfskn」,通過充分的進化,就可以得到一條真理序列「iamhandsome」(啪)。這個過程其實是在模擬生物的進化,每代生物會發生隨機變異,然後被自然自然淘汰只剩下最優秀的一部分,再由這部分生出下一代(我設定的字母組有1000個,相當於一個有1000個個體的種群)。下面由我介紹程序正確的打開姿勢:

打開程序,首先需要輸入的是序列長度。比如說想進化的單詞是evolution,那就輸入9回車;如果是life,就是4,回車。

然後需要輸入的是初始變異序列,長度須與序列長度一致,多餘的字母會被捨去。這裡需要麻煩各位讀者老爺的是,由於筆者水平有限,不會將字母轉化為自然數序列(如果哪位大神願意指教,請在評論區留言,感謝),因此各位需要先將字母轉化為數字:a=0,b=1,c=2,......,y=24,z=25。以abcd為例,就是0(空格或回車)、1(空格或回車)、2(空格或回車)、3(回車)。之後程序會幫助確認序列(不過各位應該也是臉滾鍵盤選的序列)。

同樣的道理,輸入目標序列。以life為例,就是11(空格或回車)、8(空格或回車)、5(空格或回車)、4(空格或回車)。

最後需要輸入的是兩個重要參數:突變率和選擇率,單位都是萬分之一,輸入數據是正整數(當然你輸0也是可以的,看代碼跳也很有意思的#(滑稽))。之後程序會告訴你初始差異的大小。調節突變率和現實率是成功的關鍵。

所有參數輸入完成後界面類似下方

由於程序模擬了突變的隨機性,因此即使是完全相同的參數,兩次運行的結果也會有差異,進化的代數和過程都很可能不相同。注意:需要仔細調節突變率和選擇率。突變率太高選擇率太低,優秀的變異結果很難保留;突變率太低選擇率太高,進化的速度又十分緩慢——二者都會導致難以進化到想要的序列。下面是三次運行上圖參數的結果,可以看出差異還是很明顯的。

接下來就看各位讀者的探索了。

為了便於交流,在末尾附上源代碼,歡迎大家討論,指出筆者的不足。筆者是編程新手,求輕噴

#include<iostream>#include<cmath>#include<ctime>using namespace std;int main(){double a,b;int var,var0,i,j,h,h0,min,minrep,min0,k,n,ge,x,s0; //var0代表突變個數 var輔助循環ge=0;min=1000;min0=1000;minrep=0;int o[1000][100];int o0[100];int oo[100];int s[1000];int m[1000];int site[1000];int value[1000];cout<<"STEP1 請輸入序列長度(個字母)";cin>>x;cout<<endl<<"STEP2 請輸入變異的初始字母序列(數字輸入,a=0,b=1,c=2,...z=25)"<<endl;for (i=0;i<x;i++) cin>>o0[i];cout<<"請確認初始序列";for(i=0;i<x;i++){switch(o0[i]) {case 0:cout<<"a";break;case 1:cout<<"b";break;case 2:cout<<"c";break;case 3:cout<<"d";break;case 4:cout<<"e";break;case 5:cout<<"f";break;case 6:cout<<"g";break;case 7:cout<<"h";break;case 8:cout<<"i";break;case 9:cout<<"j";break;case 10:cout<<"k";break;case 11:cout<<"l";break;case 12:cout<<"m";break;case 13:cout<<"n";break;case 14:cout<<"o";break;case 15:cout<<"p";break;case 16:cout<<"q";break;case 17:cout<<"r";break;case 18:cout<<"s";break;case 19:cout<<"t";break;case 20:cout<<"u";break;case 21:cout<<"v";break;case 22:cout<<"w";break;case 23:cout<<"x";break;case 24:cout<<"y";break;case 25:cout<<"z";break;default: cout<<endl<<endl<<" input error,please reopen the program"<<endl;goto end; }}cout<<endl;cout<<endl<<"STEP3 請輸入目標初始字母序列(同上,要求長度相同)"<<endl;for(i=0;i<x;i++) cin>>oo[i];cout<<"請確認目標序列";for(i=0;i<x;i++){switch(oo[i]) {case 0:cout<<"a";break;case 1:cout<<"b";break;case 2:cout<<"c";break;case 3:cout<<"d";break;case 4:cout<<"e";break;case 5:cout<<"f";break;case 6:cout<<"g";break;case 7:cout<<"h";break;case 8:cout<<"i";break;case 9:cout<<"j";break;case 10:cout<<"k";break;case 11:cout<<"l";break;case 12:cout<<"m";break;case 13:cout<<"n";break;case 14:cout<<"o";break;case 15:cout<<"p";break;case 16:cout<<"q";break;case 17:cout<<"r";break;case 18:cout<<"s";break;case 19:cout<<"t";break;case 20:cout<<"u";break;case 21:cout<<"v";break;case 22:cout<<"w";break;case 23:cout<<"x";break;case 24:cout<<"y";break;case 25:cout<<"z";break;default: cout<<endl<<endl<<" input error,please reopen the program"<<endl;goto end; }}cout<<endl;s0=0;for(i=0;i<x;i++) s0+=(o0[i]-oo[i])*(o0[i]-oo[i]); //caculate the distancecout<<endl<<"初始差距s為"<<endl<<s0;cout<<endl;cout<<endl<<"STEP4 請輸入突變率(正整數)var0(‰)"<<endl;cin>>var0;cout<<endl;cout<<"STEP5 請輸入選擇率(整數,不建議超過100)n(‰)" <<endl;cin>>n;system ("pause");cout<<endl<<"please wait a few seconds"<<endl;srand(time(0)); //引入時間函數模擬隨機過程for(j=0;j<1000;j++) {for(i=0;i<x;i++) o[j][i]=o0[i];}j=0;for(h0=0;h0<1000;h0++,j++){ for(var=0;var<var0;var++){ //sb=rand()%x;site[var]=b; //給數組中的隨機序數(x以內非負整數)數字進行變異} //efor(var=0;var<var0;var++){ //s a=1+rand()%25000; value[var]=a;if(value[var]>25)value[var]=0; } //給數組加一個26內的隨機整數 efor(var=0;var<var0;var++){o[j][site[var]]=o[j][site[var]]+value[var]; //完成變異 sif(o[j][site[var]]>25){o[j][site[var]]=o[j][site[var]]-26;}} //e} //e //for h0 結束的地方while(min0>0) //在差異縮小到零之前循環{ //sge=ge+1;for(j=0;j<1000;j++){ s[j]=0;for(i=0;i<x;i++) s[j]+=(o[j][i]-oo[i])*(o[j][i]-oo[i]);} //caculate the distancefor(min=s[0],j=0;j<1000;j++){if(s[j]<=min) min=s[j],minrep=j;}min0=min;for(i=0;i<x;i++){switch(o[minrep][i]){case 0:cout<<"a";break;case 1:cout<<"b";break;case 2:cout<<"c";break;case 3:cout<<"d";break;case 4:cout<<"e";break;case 5:cout<<"f";break;case 6:cout<<"g";break;case 7:cout<<"h";break;case 8:cout<<"i";break;case 9:cout<<"j";break;case 10:cout<<"k";break;case 11:cout<<"l";break;case 12:cout<<"m";break;case 13:cout<<"n";break;case 14:cout<<"o";break;case 15:cout<<"p";break;case 16:cout<<"q";break;case 17:cout<<"r";break;case 18:cout<<"s";break;case 19:cout<<"t";break;case 20:cout<<"u";break;case 21:cout<<"v";break;case 22:cout<<"w";break;case 23:cout<<"x";break;case 24:cout<<"y";break;case 25:cout<<"z";break; }}cout<<" s="<<min<<" (第"<<ge<<"代)"<<endl;while(min<10000){for(j=0,k=0;j<1000;j++){if(s[j]=min) continue;m[k]=j;k=k+1;}min=min+1;if(k>n) break;}for(h=0;h<n;h++){for(i=0,i<x;i++;)o[h*1000/n][i]=o[m[h]][i];j=h*1000/n;for(h0=0;h0<1000/n;h0++,j++){for(var=0;var<var0;var++){b=rand()%x;site[var]=b;} //給數組中的隨機序數(x以內非負整數)數字進行變異for(var=0;var<var0;var++){ a=1+rand()%25000; value[var]=a;if(value[var]>25)value[var]=0; } //給數組加一個26內的隨機整數for(var=0;var<var0;var++){o[j][site[var]]=o[j][site[var]]+value[var]; //完成變異if(o[j][site[var]]>25){o[j][site[var]]=o[j][site[var]]-26;}}} //for h0 結束的地方} //for h=0 end}//while endend:cout<<endl<<"製作:鏡子文明(知乎ID:然兮)"<<endl;cout<<"歡迎關注我們的微信公眾號:南京大學科幻愛好者協會(賬號:njusfa)"<<endl<<"究想像之靈飛,切現實之深沉。"<<endl<<endl;system ("pause");return 0;}

推薦閱讀:

二十餘年來鳥類起源研究(六):展望
人類進化史的進化狀態是什麼樣的?
為什麼脊椎動物沒有進化出六條腿?
如果達爾文的進化論被推翻,那麼人類到底起源自何方?
21世紀,中國人必須面對的進化問題

TAG:進化 | 計算機 | 生物學 |