2010-12-12 26 views
1

遺伝的アルゴリズムプログラムがより速い結果を返すのを助けるために、コードを追加または省略する効果的な手段を探しています。このプログラムの目標は、文字列を受け入れ、可能な限り一致する他の文字列を作成することです。新しく作成された文字列は、他のものと最も近い(上位5)の文字列と一致し、子孫を生成します(長さに影響を与えずに文字列に新しい乱数を入れる突然変異を含む)。それはすべて正常に動作しますが、より長いストリング(4以上)の一部を完全に一致させるには、世代の数え切れないほどの世代が必要です。 tl; drの長さは残念ですが、ここに私の現在のコードがあります。離れて批判する!C++での遺伝的アルゴリズムの最適化

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

答えて

0

アルゴリズムのほとんどの領域(フィットネス評価など)ごとに個別に実行することができます。本当に素晴らしいスピードアップのために、これらを並列に実行することをお勧めします。CUDAは良いアーキテクチャです。

+0

私はCUDAのようなことができることをもっと知りたいと思っています。私はまだ初心者プログラマーの方です。 –

0

残念ながら、遺伝的アルゴリズムの性質は、パラメータを微調整して解決策をより迅速に見つけることができるかどうかを確認する必要があることを意味します。トップ10個、トップ7、トップ3をクローンしてみてください。トップ20を(例えば)50に変更してください。突然変異率を増減してください。

悲しいことに、悲しいことに、この種の調整を行わずに「正しい」パラメータを決定できるようにするには、GAについて十分理解していません。

コード最適化は、各世代の実行速度を向上させる可能性のある個別の質問ですが、問題が発生していると思われるのは、世代が多すぎるためです。

+0

正確に。私は "完璧な"答えを得るために必要な世代の量を減らすことを意味しました。 –

+0

ダウンボートがありましたか?どうして? –

+0

答えが間違っていると思われる場合は、説明してください。みんな助けてくれるでしょう! –

0

GAのパラメータを確認する必要があります。あなたの人口は、そのような単純な計算にはあまりにも小さいです。 10または100Kでなくても、1000以上にするのは問題ありません。プールには、すぐれた結果に収束するのに十分なソリューションがないだけです。

さらに、あなたのエリート主義(あなたが次世代のために複製する候補者の数)はかなり高いです。あなたは一般に、エリート主義のために2%を上回ることを望んでいません。

また、クロスオーバー機能をどのように行っているかを見ることもできます。一般的に、上位20%だけでなく、全人口のクロスオーバーを実行したいと考えています。あなたのクローンされていない値の95すべてをクロスオーバー機能に渡すと、あなたの人口の多様性が増します。

キャメロン氏によると、問題はコードではなくパラメータにある可能性がありますが、それはまったく別の問題ですが、これはあなたを助けるはずです。がんばろう!

+0

問題の事実は、私は具体的にはトップ20を持つように割り当てられたということです。 –

+0

人口が多いかもしれませんが、小さな人口進化アルゴリズムに関する豊富な文献を見る価値があります。あなたは2%ものについての参考資料を挙げることができますか?それは調整する必要がある別のパラメータです。他のケースでは2%が時々動作し、0.2%または20%が機能します。私は "十字架のすべて"のビットに同意します。まったくの広告として:新しい遺伝物質を見つけるための突然変異の使用に関してSkinner * et al *を見てください:) –

+0

参考文献は、Mrs PetersonとF. Moore博士の仕事私自身のEC研究の個人的な経験と同様に、おそらく少しばかげていますが、読むIMOの価値があります。そして、あなたが指摘しているように、それは他のコントローラを調整するのと同じくらい難しく、速いルールではありませんが、上のエリート主義を高めることで肯定的なパフォーマンスを得た場所で使用したGAは思い出せません。 – Raskolnikov

5

GAがうまく収束しない大きな理由の1つは、フィットネス機能です。プログラマーの他の部分での潜在的なコーディングエラーを無視して、あなたがしているのは完全に一致した文字だけを報いることです。フィットネスランドスケープは(!私のアスキーアートを恐れて)このようなものです:Gは、希望の文字をある

 
___________ ___________ 
      | | 
      |_| 
a b c d e f G h i j k l m 

。このアルゴリズムでは、Gを見つけ出す方法はわかりませんが、幸いです。あなたは基本的に無作為化された手紙によるbrute-force検索を実装しました。

適合関数を適切なソリューションに近似すると、収束ははるかに速くなります。また、母集団のパラメータ、突然変異、クロスオーバーなどを微調整してください。

+0

"適性関数が正しい解に近似し、収束がはるかに速くなる":必ずしもそうではありません...演算子が "距離"と同じ概念を持っているかどうかによって異なります。コードから、私は彼らがそうであると確信していない。突然変異演算子を変更して文字値から1を引いたり引いたりした場合、この答えは正しいです。突然変異が新しいランダムな値を選択した場合、この答えは正しくありません。 GAは難しいです! –

+0

コードをより詳しく読むことから、私はますますこれが*働かないと確信しています。クロスオーバは無作為な親対立遺伝子から選択し、突然変異は本質的に存在しない(むしろ、下の75個の個体はランダムに生成される)。単一の対立遺伝子に任意の種類の勾配降下を行うことができるので、このようにフィットネス機能を変更することは基本的に何もしません。 *アイデア*が良いので、私はダウンボートしませんが、この場合には遺伝子操作者にも変更が必要です。 –

+0

私は答えとコメントの両方に同意する必要があります。ハミング距離をとるのではなく、オリジナルからの距離に基づいて報酬を与えるフィットネス機能を調整すると、突然他のキャラクターをランダムに選択するのではなく、突然変異関数を変更してキャラクターを少量だけ増減させることができます。 – Raskolnikov

関連する問題