• 締切済み

遺伝的アルゴリズム

遺伝的アルゴリズムのプログラムを作っているのですがサンプルソースの下の関数のやってこるこがよく意味がわかりません。よかったら解説 お願いします。 // 一点交叉 void one_point_crossover(struct genotype *ind) { int i, ia, ib; // 個体インデックス int j; // 遺伝子座インデックス int c; // 交叉点 int test[M]; // 個体の利用フラグ int temp[N]; // 遺伝子を入れ替えるための仮変数 // 4/24修正 int r; // 乱数値 for(i=0; i<M; i++) test[i] = 0; ia = ib = 0; for(i=0; i<M/2; i++) { // 個体をランダムにペアリング for(; test[ia]==1; ia=(ia+1)%M); test[ia] = 1; r = random() % (M-2*i) + 1; while(r>0) { ib=(ib+1)%M; for(; test[ib]==1; ib=(ib+1)%M); r--; } test[ib] = 1; // 個体iaとibを交叉 if(flip(Pc)) { c = random() % N; for(j=0; j<c; j++) { temp[j] = ind[ia].gene[j]; ind[ia].gene[j] = ind[ib].gene[j]; ind[ib].gene[j] = temp[j]; } } } } // End of one_point_crossover()

みんなの回答

  • sgwjn
  • ベストアンサー率70% (47/67)
回答No.1

一点交叉は、2つの個体の遺伝情報をある一点の後で置換するアルゴリズムだったと思います。それを踏まえて解説を入れると、 for(i=0; i<M; i++) {   test[i] = 0;   // ペアで使用済みの個体を識別するフラグの初期化 } ia = ib = 0; for(i=0; i<M/2; i++)         // 全個体に対し、一点交叉を実行 {   // 個体をランダムにペアリング   for(; test[ia]==1; ia=(ia+1)%M);  // 未使用の個体を1つ選択し     test[ia] = 1;           // その個体の使用済みフラグを立てる   r = random() % (M-2*i) + 1;    // 2つ目の個体決定用の乱数生成   while(r>0)   {     ib=(ib+1)%M;            // 2つ目の個体を決定     for(; test[ib]==1; ib=(ib+1)%M);       r--;   }   test[ib] = 1;            // 2つ目の個体の使用済みフラグを立てる   // 個体iaとibを交叉   if(flip(Pc))   {     c = random() % N;           // ランダムに交叉位置を決定     for(j=0; j<c; j++)     {       temp[j] = ind[ia].gene[j];      // 交叉位置の前後で遺伝情報を置換       ind[ia].gene[j] = ind[ib].gene[j];       ind[ib].gene[j] = temp[j];     }   } } プログラムで見ると分かりにくいですが、要するに交叉させる個体ia、ibを選択して、交叉位置をランダムに決定し、その位置の後で遺伝情報を入れ替えて個体ia'、ib'を作成しているだけです。 例) 個体ia [1, 2, 3, 4, 5] 個体ib [6, 7, 8, 9, 10] []内が遺伝情報      ↓      ↓交叉位置を3とすると(先頭1始まり)      ↓ 個体ia' [1, 2, 3, 9, 10] 個体ib' [6, 7, 8, 4, 5]  (交叉位置を含めるかはプログラムによる) 後、このプログラムはネストが深いので、書き込む際にはインデントを入れた方が見やすいですよ。

関連するQ&A

  • C言語 遺伝的アルゴリズムでのエラーについて

    再度質問させていただきます。 以下のプログラムを実行するとsegmentation faultが出たり出なかったりします。 いまいち原因が分からないので回答お願いします。 ちなみに目的としては、 0~1の乱数が複数個与えられたときに、与えられた乱数を2つのグループに分け、その2グループの差ができるだけ小さくなるようにする。 といったものです。 よろしくお願いします。 #include<stdio.h> #include<stdlib.h> #include<time.h> //染色体の数 #define Number_of_ch 10 //エリート選抜の割合 #define Selection 0.3 //交叉率 #define Cross_ratio 0.7 //突然変異率 #define Mutation_ratio 0.2 //ループ回数 #define Number_of_loop 100 int main(int argc , char *argv[]) { int f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,x,y,z; long int Number_of_gene = argc-1;//遺伝子の数 int chromosome[Number_of_ch][Number_of_gene],distmin[Number_of_gene];//染色体と遺伝子 int best_chromosome[Number_of_gene],Number_of_cross=0,ch_1=0,ch_2=0,point=0,temp=0,temp_1=0,temp_2=0,abc=0,loop=0; double real_Number[Number_of_gene] , dist[Number_of_ch]; double best = 100.0; double sum0 = 0.0 , sum1 = 0.0 ; //入力値の記録 for(i=0 ; i<Number_of_gene ; i++){ real_Number[i] = atof(argv[i+1]); } srand((unsigned)time(NULL)); //染色体の初期化 for(j=0 ; j<Number_of_ch ; j++){ for(k=0 ; k<Number_of_gene ; k++){ chromosome[j][k] = rand() % 2;//0 or 1のグループ分け } } //----------------------ループ開始------------------------ while(loop < Number_of_loop){ //差分 for(l=0 ; l<Number_of_ch ; l++){ for(m=0 ; m<Number_of_gene ; m++){ if(chromosome[l][m] == 0){ sum0 = sum0 + real_Number[m]; } else{ sum1 = sum1 + real_Number[m]; } } if(sum0 > sum1){ dist[l] = sum0 - sum1; } else{ dist[l] = sum1 - sum0; } } //評価と記憶 for(n=0 ; n<Number_of_ch ; n++){ if(dist[n] < best){ best = dist[n]; for(o=0 ; o<Number_of_gene ; o++){ best_chromosome[o] = chromosome[n][o]; } } } //ソート for(p=0 ; p<Number_of_ch ; p++){ for(q=1 ; q<Number_of_ch-p+1 ; q++){ if(dist[q-1] > dist[q]){ for(r=0 ; r<Number_of_gene ; r++){ distmin[r] = chromosome[q][r]; chromosome[q][r] = chromosome[q-1][r]; chromosome[q-1][r] = distmin[r]; } } } } //エリートの選抜 for(s=Number_of_ch*Selection ; s<Number_of_ch ; s++){ for(t=0 ; t<Number_of_gene ; t++){ chromosome[s][t] = best_chromosome[t]; } } //交叉 Number_of_cross = Number_of_ch * Cross_ratio; for(u=0 ; u<Number_of_cross ; u++){ ch_1 = (Number_of_ch-1) * (rand()/32767); ch_2 = (Number_of_ch-1) * (rand()/32767); point = (Number_of_gene-1) * (rand()/32767); for(x=point ; x<Number_of_gene ; x++){ temp_1 = chromosome[ch_1][x]; for(y=0 ; y<Number_of_gene ; y++){ if(chromosome[ch_1][x] == chromosome[ch_2][y]){ temp_2 = chromosome[ch_2][x]; chromosome[ch_2][x] = chromosome[ch_2][y]; chromosome[ch_2][y] = temp_2; } for(z=0 ; z<Number_of_gene ; z++){ if(chromosome[ch_2][x] == chromosome[ch_1][z]){ chromosome[ch_1][x] = chromosome[ch_1][z]; chromosome[ch_1][z] = temp_1; } } } } } //突然変異 for(f=0 ; f<Number_of_cross ; f++){ for(g=0 ; g<Number_of_gene ; g++){ if(rand()/32767 < Mutation_ratio){ abc = (Number_of_gene-1) * (rand()/32767); temp = chromosome[f][g]; chromosome[f][g] = chromosome[f][abc]; chromosome[f][abc] = temp; } } } loop = loop + 1; } //結果の出力 printf("# best = %f \n",best); for(h=0 ; h<Number_of_gene ; h++){ printf("%d",best_chromosome[h]); } printf("\n"); }

  • C言語 遺伝的アルゴリズムでのエラーについて

    与えられた乱数を二つのグループにわけ、その差が小さくなるようなプログラムを書いているつもりです。 が、コンパイルし、実行したところsegmentation fault が表示されます。 segmentation fault が表示される理由はわかっていますが、どこでそういった現象がおこっているのか判断できない状況です。 どなたかよろしくお願いします。 #include<stdio.h> #include<stdlib.h> #include<time.h> //染色体の数 #define Number_of_ch 10 //エリート選抜の割合 #define Selection 0.3 //交叉率 #define Cross_ratio 0.7 //突然変異率 #define Mutation_ratio 0.1 //ループ回数 #define Number_of_loop 100 int main(int argc , char *argv[]) { int f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,x,y,z; int Number_of_gene = argc-1;//遺伝子の数 int chromosome[Number_of_ch][Number_of_gene],distmin[Number_of_gene];//染色体と遺伝子 int best_chromosome[Number_of_gene],Number_of_cross=0,ch_1=0,ch_2=0,point=0,temp=0,temp_1=0,temp_2=0,abc=0,loop=0; float real_Number[Number_of_gene] , dist[Number_of_ch] , best = 100.0; float sum0 = 0.0 , sum1 = 0.0 ; //入力値の記録 for(i=0 ; i<argc ; i++){ real_Number[i] = atof(argv[i+1]); } srand((unsigned)time(NULL)); //染色体の初期化 for(j=0 ; j<Number_of_ch ; j++){ for(k=0 ; k<Number_of_gene ; k++){ chromosome[j][k] = rand() % 2;//0 or 1のグループ分け } } //----------------------ループ開始------------------------ while(loop < Number_of_loop){ //差分 for(l=0 ; l<Number_of_ch ; l++){ for(m=0 ; m<Number_of_gene ; m++){ if(chromosome[l][m] == 0){ sum0 = sum0 + real_Number[k]; } else{ sum1 = sum1 + real_Number[k]; } } dist[l] = abs(sum1 - sum0); } //評価と記憶 for(n=0 ; n<Number_of_ch ; n++){ if(dist[n] < best){ best = dist[n]; for(o=0 ; o<Number_of_gene ; o++){ best_chromosome[o] = chromosome[n][o]; } } } //ソート for(p=0 ; p<Number_of_ch ; p++){ for(q=1 ; q<Number_of_ch-p+1 ; q++){ if(dist[q-1] > dist[q]){ for(r=0 ; r<Number_of_gene ; r++){ distmin[r] = chromosome[q][r]; chromosome[q][r] = chromosome[q-1][r]; chromosome[q-1][r] = distmin[r]; } } } } //エリートの選抜 for(s=Number_of_ch*Selection ; s<Number_of_ch ; s++){ for(t=0 ; t<Number_of_gene ; t++){ chromosome[s][t] = best_chromosome[t]; } } //交叉 Number_of_cross = Number_of_ch * Cross_ratio; for(u=0 ; u<Number_of_cross ; u++){ ch_1 = (Number_of_ch-1) * (rand()/32767); ch_2 = (Number_of_ch-1) * (rand()/32767); point = (Number_of_gene-1) * (rand()/32767); for(x=point ; x<Number_of_gene ; x++){ temp_1 = chromosome[ch_1][x]; for(y=0 ; y<Number_of_gene ; y++){ if(chromosome[ch_1][x] == chromosome[ch_2][y]){ temp_2 = chromosome[ch_2][x]; chromosome[ch_2][x] = chromosome[ch_2][y]; chromosome[ch_2][y] = temp_2; } for(z=0 ; z<Number_of_gene ; z++){ if(chromosome[ch_2][x] == chromosome[ch_1][z]){ chromosome[ch_1][x] = chromosome[ch_1][z]; chromosome[ch_1][z] = temp_1; } } } } } //突然変異 for(f=0 ; f<Number_of_cross ; f++){ for(g=0 ; g<Number_of_gene ; g++){ if(rand()/32767 < Mutation_ratio){ abc = (Number_of_gene-1) * (rand()/32767); temp = chromosome[f][g]; chromosome[f][g] = chromosome[f][abc]; chromosome[f][abc] = temp; } } } loop = loop + 1; } //結果の出力 printf("# best = %f \n",best); for(h=0 ; h<Number_of_gene ; h++){ printf("%d",best_chromosome[h]); } printf("\n"); }

  • 遺伝的アルゴリズムのプログラミングについてですが・・・

    遺伝的アルゴリズムのプログラムの基本的な流れが↓のページ http://www.sist.ac.jp/~suganuma/kougi/other_lecture/SE/opt/GA/GA.htm に 【1.初期化 2.生物集団の評価 3.交叉 4.突然変異 5.各個体の評価 6.淘汰】と書かれてあるのですが、 f(x) = sin(3x) + 0.5sin(9x) + sin(15x + 50) [0.1]区間の最大値を求める↓のプログラム http://www.sist.ac.jp/~suganuma/cpp/3-bu/18-sho/genetic/C++/gene_f.txt  に当てはめるとどの部分がどこに当たるのでしょうか…(また、このプログラムはどこからどのように読んでいけばいいのでしょうか…)。一応コメントが書かれていますがよく分かりません><; わかる方がいらっしゃいましたらよろしくお願いしますm( _ _ )m また、遺伝的アルゴリズムのプログラミングをする際の注意点があれば教えてください。

  • 二次配列のqsort

    二次配列のqsortについて分かる方に教えて頂きたいのですが 一段落のプログラムを載らせていただきました.count3[j][i]をバブルソートで降順でやってみましたが高速が要求されるため,qsortを使ってやり直したいのですが (ちなみにcount1[j][i],count2[j][i]は前で定義してあります.count4[j][i]にはiの順番を記憶するための二次配列です)  ぜひともよろしくおねがいします. int ind_near_search(int j,int t) { int i,var_num,count3[IND][VAR],count4[IND][VAR],temp1,temp2,num=0,m=0; for(i=0;i<VAR;i++){ if(individual[j].x[i]==1){ //変数が1と0の場合分け count2[j][i]=t-count[j][i]; }else{ count2[j][i]=count[j][i]; } if(individual[j].x[i]==1){ //全てcount3に値を入れる count3[j][i]=count2[j][i]; }else{ count3[j][i]=count[j][i]; } } for(i=0;i<VAR;i++){ count4[j][i]=num++; } for(m=0;m<VAR-1;m++){ for(i=0;i<VAR;i++){ //バブルソートにより降順に並べ換え if(count3[j][i]<count3[j][i+1]){ temp1=count3[j][i]; count3[j][i]=count3[j][i+1]; count3[j][i+1]=temp1; temp2=count4[j][i]; //count4にはcount3の並べ替え後の対応する番号を入れる count4[j][i]=count4[j][i+1]; count4[j][i+1]=temp2; } } } for(i=0;i<VAR;i++){ var_num=count4[j][i]; //count4の大きい順番からその番号をvar_numに渡す if(individual[j].x[var_num]==0){//0と1の場合分け individual[j].x[var_num]=1; }else{ individual[j].x[var_num]=0; }

  • クイックソートのアルゴリズム

    http://www1.cts.ne.jp/~clab/hsample/Sort/Sort9.html こちらにあったソースを改造しました。 #include <stdio.h> void QSort(int x[ ], int left, int right) {   int i, j, temp;   int pivot;   i = left;   j = right;   pivot = x[(left + right) / 2]; // 6,5,4,3 // pivot=4   while (1) {   while (x[i] <= pivot) i++; // サイトのソースは = が無かったから付けた // 2回目のループでは j=2   while (pivot < x[j]) j--; // 2回目のループで x[-1] を参照しませんか? // 初回ループで i=0, j=3   if (i >= j) break;   temp = x[i]; x[i] = x[j]; x[j] = temp; // 交換   i++; j--;   }   ShowData(x, 10); // 途中経過を表示   if (left < i - 1) QSort(x, left, i - 1);   if (j + 1 < right) QSort(x, j + 1, right); } void ShowData(int x[ ], int n) {   int i;   for (i = 0; i < n ; i++) printf("%d ", x[i]);   printf("\n"); } void main(void) {   int x[] = {6, 3, 1, 7, 0, 4, 8, 5, 2, 9};   int n = 10;   printf("ソート前:\n");   ShowData(x, n);   printf("ソート中:\n");   QSort(x, 0, n - 1);   printf("ソート後:\n");   ShowData(x, n); } テストデータが 6,5,4,3 だと、 2回目のループで x[-1] を参照しませんか? 今コンパイラが使えません。 教えてください。 それと、=を付けたんですが、付けないといけませんよね?

  • 数独を解くアルゴリズム

    バックトラック法で解いているのですが、どこがおかしいのか見当もつかないので教えてください。 コンパイルエラーはありません。 表示の関数は省いてあります。 よろしくお願いします。 #include <stdio.h> #define M 3 //小さいブロックのサイズ #define N M*M //全体のサイズ #define MTX N*N //全体のマス数 int sudoku[N][N]={    {0,2,4,5,0,0,6,0,0},    {0,0,6,3,2,0,0,0,4},    {0,0,5,0,9,0,0,8,3},    {0,0,8,4,0,3,0,0,1},    {0,6,1,9,0,0,4,3,0},    {7,0,0,1,0,0,5,0,0},    {8,3,0,0,4,0,9,0,0},    {4,0,0,0,3,5,8,0,0},    {0,0,7,0,0,9,3,4,0}    }; /* 候補がOKかどうかチェック */ int OKkouho(int x, int y, int k) {    int i,j;    int p,q;    for(i=0; i < N; i++){ //その行に候補は入るか       if(sudoku[y][i] == k)          return 0;    }    for(j=0; j < N; j++){ //その列に候補は入るか       if(sudoku[j][x] == k)          return 0;    }    p = x/M*M;    q = y/M*M;    //そのブロックに候補は入るか    for(j = q; j < q+M; j++){       for(i = p; i < p+M; i++){          if(sudoku[j][i] == k)             return 0;       }    }    return 1; } void Solve(int level) {    int k;    int x,y;    if(level >= MTX){       printf("OK");       return;    }    x = level%N;    y = level/N;    if(sudoku[y][x])       Solve(level+1);    else{       for(k = 1; k <= N; k++){          if(OKkouho(x,y,k)){             sudoku[y][x] = k;             Solve(level+1);             sudoku[y][x] = 0;             }       }    } } int main(void) {    Solve(0);    return 0; }

  • 配列について

      class Array01{ public static void main(String[] args){ int[][] ia = {{11,12},{21},{41,42,44}}; for(int i = 0; i < ia.length; i++){ for(int j = 0; j < ia[i].length; j++ ){ System.out.print(ia[i][j] + " "); } System.out.println(); } } } } (i < ia.length) と (j < ia[i].length)のとこの意味が分かりません。特にiaとia[i]の違いなんか教えてもらえると助かります。for文については理解してるんですが・・・

    • ベストアンサー
    • Java
  • 遺伝子アルゴリズムの2点交叉について教えてください

    下記のプログラムを改良して2点交叉にしたいのですが、遺伝子アルゴリズムもC++も初心者なので、よくわかりません。どなたかお知恵を貸してください。 #include <stdio.h> #include <stdlib.h> #include <time.h> #include "come.h" int kousa() { unsigned int max=100; unsigned int max2=17; int a,b,c,d; int i,v,w,y,n,o,k,p,f; char kari[1][17]; w=0;//カウンタ n=0; srand((unsigned)time(NULL)); for(v=0;v<100;v++) { for(i=0;i<17;i++) { get[v][i]=next[v][i]; //next[175][17]からget[100][17]へコピーする(親) } } for(o=0;o<100;o++) { for(k=0;k<17;k++) { take[o][k]=next[v][k]; //next[175][17]からtake[100][17]へコピーする(子) } } for(d=0;d<50;d++) { a=(rand()%max); //1つ目の交叉する列を見つける b=(rand()%max); //2つ目の交叉する列を見つける c=(rand()%max2); //交叉ポイント見つける for(;c<17;c++) //1点交叉 { kari[n][c]=get[a][c]; get[a][c]=get[b][c]; get[b][c]=get[n][c]; } for(y=0;y<17;y++) { take[w][y]=get[a][y]; //get[100][17]からtake[50][17]へコピー take[w+1][y]=get[b][y]; } w=w+2; } for(p=0;p<100;p++) { for(f=0;f<17;f++) { next[nextpop][f]=take[p][f]; } nextpop++; } return 0; }

  • C++ ソートのやり方

    僕が作ったプログラムで、これはバブルソートなのかわからないので教えてください。 また、ほかのソートの仕方も教えてください。 よろしくお願いします。 汎用関数を使っているのでわかりにくいかもしれないですがお願いします。 #include <iostream> using namespace std; template <class X>void Sort(X *data, int size) { X temp; for (int i = 0; i < size; i++){ for (int j = i + 1; j < size; j++){ if (data[i]>data[j]){ temp = data[i]; data[i] = data[j]; data[j] = temp; } } } } int main() { int i[10]{1, 4, 3, 5, 2, 10, 2, 7, 6, 8}; char c[10]{'c', 'b', 'z', 'a', 'x', 'y', 'j', 'n', 'm', 'r'}; Sort(c, 10); Sort(i, 10); for (int j = 0; j < 10; j++){ cout << i[j] << ' '; } cout << endl; for (int j = 0; j < 10; j++){ cout << c[j] << ' '; } cout << endl; getchar(); return 0; }

  • 配列について

    以下の配列についての問題でわからないことがあるので、教えてください。 /* x と y の積を求める。 */ #include <stdio.h> int main(void) { int x[2][3] = {{1,2,3}, {4, 5, 6}}; int y[3][2] = {{1, 5}, {5, 3}, {8, 1}}; int ans[2][2] = {0}; int i, j, k, temp; for(i = 0; i < 2; i++) { for (k = 0; k < 2; k++) { temp = 0; for(j = 0; j < 3; j++) { temp += x[i][j] * y[j][k]; } ans[i][k] = temp; } } for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { printf("%4d",ans[i][j]); } putchar('\n'); } return(0); } 以下の部分について詳しく説明してもらえないでしょうか? int ans[2][2] = {0};  int i, j, k, temp; for(i = 0; i < 2; i++) { for (k = 0; k < 2; k++) { temp = 0; for(j = 0; j < 3; j++) { temp += x[i][j] * y[j][k]; } ans[i][k] = temp; } }

専門家に質問してみよう