[英]Genetic Algorithm optimization in C++
我正在尋找添加或省略代碼的有效方法,以幫助我的遺傳算法程序更快地返回結果。 該程序的目標是接受一個字符串並創建其他盡可能匹配的字符串。 不論哪個新制作的字符串與最接近的(前5個)字符串匹配,都會產生后代(其中一些字符串的突變會在字符串中添加新的隨機數而不影響長度)。 一切正常,但要花費一些世代才能使更長的字符串(4個及以上)完全匹配。 很抱歉tl; dr的長度,但這是我當前的代碼。 批評一下!
#include "stdio.h"
#include "fstream"
#include "ctime"
#include "iostream"
#include "string"
#include "windows.h"
#define CHARACTERS 16
#define STRINGS 100
/*
Enter String(max 16 chars)
Generate 100 words of the same length
Check for Fitness(how close each word is to the string)
Every generation: display top 5
Clone the top 5
Top 20 reproduce(mix each other's chars)
1/1000 chance the children might mutate(each newly mixed string or char might have a completely random number)
*/
typedef struct _stringHolder
{
char randString[CHARACTERS];
int fitness;
}StringHolder;
//Randomly generate 100 words
void generate(char *myString, StringHolder *SH)
{
unsigned seed = time(0);
srand(seed);
//int i = 0;
int j = 0;
char randChar;
//char showString[CHARACTERS];
for(int i=0; i<STRINGS; i++)
{
for(int j=0; j<strlen(myString); j++)
{
randChar = ('a' + (rand() %26));
SH[i].randString[j] = randChar;
}
//limiter so that it doesn't crash
SH[i].randString[strlen(myString)] = 0;
}
}
//Check the similarity of the random strings to the original string.
void getFitness(char *myString, StringHolder *SH)
{
for(int i=0; i<STRINGS; i++)
{
for(int j=0; j<strlen(myString); j++)
{
if(SH[i].randString[j] == myString[j])
{ SH[i].fitness++; }
}
}
}
//Sort the strings
void sortByFitness(char *myString, StringHolder *SH)
{
bool swapped = 1;
while(swapped)
{
swapped = 0;
for(int a=0; a<STRINGS-1; a++)
{
if(SH[a].fitness < SH[a+1].fitness)
{
swapped = 1;
StringHolder temp[STRINGS];
temp[a] = SH[a+1]/*.randString[i]*/;
SH[a+1]/*.randString[i]*/ = SH[a]/*.randString[i]*/;
SH[a]/*.randString[i]*/ = temp[a];
/*if(SH[a].fitness < SH[a+1].fitness)
{ swapped = 0; }*/
}
}
}//while
}
//Clone the Top 5 strings
void cloneTopFive(char *myString, StringHolder *SH, StringHolder *cloneString)
{
for(int i=0; i<5; i++)
{
cloneString[i]/*.randString[j]*/ = SH[i]/*.randString[j]*/;
//printf("cloneString[%d] now holds %s.\n", i, SH[i].randString);
}
}
//Reproduce the Top 20 strings by mixing and matching elements between strings
void reproduceTopTwenty(char *myString, StringHolder *SH /*char *cloneString*/)
{
/*for(int h=5; h<95; h++)
{*/
for(int i=0; i<20; i++)
{
for(int j=0; j<strlen(myString)-1; j++)
{
//char temp[16];
//temp[i] =
SH[i].randString[j] = SH[1 + (rand() %20)].randString[1 + (rand() %strlen(myString)-1)];
int randomNumber;
randomNumber = (1 +(rand() %100));
if(randomNumber == 7)
{
SH[i].randString[1 + (rand() %strlen(myString)-1)] = ('a' + (rand() %26));
}
}
}
}
//Randomize the other 75 numbers and place the cloned Top 5 at the end of the String Holder(SH)
void randomizeOther75(char *myString, StringHolder *SH, StringHolder *cloneString)
{
for(int i=20; i<STRINGS; i++)
{
for(int j=0; j<strlen(myString); j++)
{
SH[i].randString[j] = ('a' + (rand() %26));
}
}
for(int i=0; i<5; i++)
{
for(int j=0; j<strlen(myString); j++)
{
int v = i + 94;
SH[v].randString[j] = cloneString[i].randString[j];
}
}
}
void printGen(char *myString, StringHolder *SH)
{
for(int i=0; i<5; i++)
{
if(SH[i].fitness == strlen(myString))
{ printf("%s has %d fitness. Perfection!\n", SH[i].randString, SH[i].fitness); }
else
printf("%s has %d fitness.\n", SH[i].randString, SH[i].fitness);
}
}
void main()
{
char myString[CHARACTERS];
StringHolder cloneString[5];
StringHolder SH[STRINGS];
for(int i=0; i<STRINGS; i++)
{ SH[i].fitness = 0; }
printf("Enter your name(no whitespaces): ");
scanf("%s", myString);
/*while(strlen(myString) >= CHARACTERS)
{
printf("Please type a string with less than 16 characters\n");
scanf("%s", myString);
}*/
//printf("%s\n", myString);
//first generation
generate(myString, SH);
int gen = 0;
while(1)
{
char x = ' ';
/* printf("Insert something. Anything!");
scanf(&x);*/
/*char newString[CHARACTERS];
for(int i=0; i<5; i++)
{
for( int j=0; j< strlen(myString); j++)
{
newString[j] = SH[i].randString[j];
}
newString[strlen(myString)] = 0;
printf("%s has %d fitness.\n", newString, SH[i].fitness);
}*/
printf("\n");
while(x==' ')
{
printf("Generation %d: \n", gen);
getFitness(myString, SH);
sortByFitness(myString, SH);
printGen(myString, SH);
for(int i=0; i<STRINGS; i++)
{ SH[i].fitness = 0; }
cloneTopFive(myString, SH, cloneString);
reproduceTopTwenty(myString, SH);
randomizeOther75(myString, SH, cloneString);
/*getFitness(myString, SH);
sortByFitness(myString, SH);
for(int i=0; i<5; i++)
{
printf("%s has %d fitness.\n", SH[i].randString, SH[i].fitness);
}
printf("\n");*/
//printf("\nInsert ' ' to continue!\n");
//scanf("%c",&x);
gen++;
}
}
GA收斂不佳的主要原因之一就是您的健身功能。 忽略程序其他部分中潛在的編碼錯誤,您要做的只是獎勵完全匹配的字母。 健身環境是這樣的(怕我的ASCII藝術!):
___________ ___________ | | |_| a b c d e f G h i j k l m
其中G是所需字母。 該算法不知道如何找到G,而是通過運氣。 您基本上已經實現了隨機的按字母順序的蠻力搜索。
使適應度函數獎勵“接近”正確的解決方案,並且收斂會更快。 還調整種群參數,突變,交叉等。
對於每個個體,算法的大多數區域(例如適應性評估)都可以獨立執行。 對於某些非常好的加速,我建議並行執行這些加速, CUDA是一個很好的架構。
不幸的是,遺傳算法的性質意味着有時您只需要調整參數,看看是否可以使其更快地找到解決方案。 嘗試克隆前10個人,前7個人或前3個人。將前20個人更改為(例如)50。增加或降低突變率。
令人遺憾的是,我們對GA的了解還不足以在不進行此類調整的情況下確定“正確的”參數。
代碼優化是一個完全獨立的問題,可以使每一代人更快地運行,但是我懷疑您遇到的問題是它需要花很多代人的時間,因此我不會在此贅述。
您需要查看GA的參數。 對於如此簡單的計算,您的人口太少了。 將其提高到至少1000(如果不是10或100K),應該沒有任何問題。 您根本沒有足夠的解決方案來迅速收斂到良好的結果。
此外,您的精英水平(您為下一代克隆的候選人數量)很高。 您通常不希望精英人士的身價超過2%。
您還可能會查看自己的交叉功能。 通常,您希望對整個人口進行交叉,而不是僅對前20%人口進行交叉。 將所有95個非克隆值傳遞到交叉函數中,您將看到總體上更多的多樣性。
正如Cameron所說,您的問題可能在於參數而不是代碼,而這是完全不同的問題,但這將對您有所幫助。 祝好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.