データ例,プログラム( MT.h は除く)
-------------------------i_data------------------------- 世代交代数 1000 乱数の初期値 12345 関数 3 出力 100 個体数 20 子供の数 20 遺伝子長 20 エリート 2 突然変異率 0.03 -------------------------program------------------------- /*************************/ /* クラス Species の定義 */ /*************************/ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "MT.h" class Species { double *pi; // 適応度 double *ro; // ルーレット板 int size; // 個体総数 int max_ch; // 子供の数の最大値 int len; // 遺伝子長 unsigned char **ind; // 集団(個体の集まり) char *pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) char *s_w; // 淘汰用指標(選択された回数) public: // コンストラクタ Species(int, int, int, long); // デストラクタ ~Species(); // 出力 void O_std(int, int out=20); // 初期設定 void I_std(); // 交叉 void C_copy(); // 親のコピー void C_unifm(int pair=0, double pr=1.0); // 一様交叉 // 突然変異 void M_alle(double); // 対立遺伝子への置換 // 淘汰 void S_roul(int elite=2); // 評価(最大適応度を返す) double Adap(int); // 個体の適応度の計算 // その他 int position(); // 場所を探す int select(); // 親の選択 }; /****************************/ /* コンストラクタ */ /* s : 個体総数 */ /* mc : 子供の数 */ /* mx : 遺伝子長 */ /* seed : 乱数の初期値 */ /****************************/ Species::Species(int s, int mc, int mx, long seed) { int i1, num; /* 乱数の初期設定 */ init_genrand(seed); /* 値の設定 */ size = s; max_ch = mc; len = mx; /* 領域の確保 */ num = size + max_ch; ind = new unsigned char * [num]; for (i1 = 0; i1 < num; i1++) ind[i1] = new unsigned char [2*len]; pi = new double [num]; pi_w = new char [num]; s_w = new char [num]; ro = new double [num]; } /****************/ /* デストラクタ */ /****************/ Species::~Species() { int i1; for (i1 = 0; i1 < size+max_ch; i1++) delete [] ind[i1]; delete [] ind; delete [] pi; delete [] pi_w; delete [] s_w; delete [] ro; } /****************************/ /* 2変数関数の最小値 */ /* coded by Y.Suganuma */ /****************************/ int main(void) { double mute; long seed; int fun, gen, max_gen, o_lvl, size, child, len, elite; // データの入力 scanf("%*s %d %*s %ld %*s %d %*s %d", &max_gen, &seed, &fun, &o_lvl); scanf("%*s %d %*s %d %*s %d", &size, &child, &len); scanf("%*s %d %*s %lf", &elite, &mute); // 種の定義 Species a(size, child, len, seed); // 初期設定 gen = 0; a.I_std(); // 個体の評価 a.Adap(fun); // 初期世代の出力 if (o_lvl > 0) a.O_std(gen); // 実行 for (gen = 1; gen <= max_gen; gen++) { // 交叉 a.C_unifm(); // 突然変異 a.M_alle(mute); // 適応度の計算 a.Adap(fun); // 淘汰 a.S_roul(elite); // 出力 if (o_lvl > 0 && gen%o_lvl == 0) a.O_std(gen); } // 最終出力 if (o_lvl == 0) a.O_std(gen-1, size+1); return 0; } /************************/ /* 適応度の計算 */ /* sw : 関数の種類 */ /************************/ double Species::Adap(int sw) { double cv = 5.0 / (pow(2.0, (double)len) - 1.0), max = 0.0, x, x1, x2, x3, y, w; int i1, i2, k = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { x = 0.0; w = 0.0; for (i2 = len-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += pow(2.0, w); w += 1.0; } x *= cv; y = 0.0; w = 0.0; for (i2 = 2*len-1; i2 >= len; i2--) { if (ind[i1][i2] > 0) y += pow(2.0, w); w += 1.0; } y *= cv; pi_w[i1] = 2; switch (sw) { case 1: x1 = x - 1.0; x2 = y - 2.0; pi[i1] = -x1 * x1 - x2 * x2; break; case 2: x1 = y - x * x; x2 = 1.0 - x; pi[i1] = -100.0 * x1 * x1 - x2 * x2; break; case 3: x1 = 1.5 - x * (1.0 - y); x2 = 2.25 - x * (1.0 - y * y); x3 = 2.625 - x * (1.0 - y * y * y); pi[i1] = -x1 * x1 - x2 * x2 - x3 * x3; break; } } if (pi_w[i1] > 0 && (k < 0 || pi[i1] > max)) { max = pi[i1]; k = 1; } } return max; } /************/ /* 初期設定 */ /************/ void Species::I_std() { int i1, i2, i3, sw1, sw2; /* 適応度 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (i1 < size) pi_w[i1] = 1; // 適応度の計算前 else pi_w[i1] = 0; // 未使用 } /* 染色体 */ for (i1 = 0; i1 < size; i1++) { sw1 = 0; while (sw1 == 0) { // 遺伝子の決定 for (i2 = 0; i2 < 2*len; i2++) ind[i1][i2] = (genrand_real3() > 0.5) ? 1 : 0; // 重複個体のチェック sw1 = 1; for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { sw2 = 0; for (i3 = 0; i3 < 2*len && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } /*********************************************/ /* 標準出力 */ /* gen : 現在の世代 */ /* out : n>0 : n個ずつ出力(default=20) */ /*********************************************/ void Species::O_std(int gen, int out) { double cv = 5.0 / (pow(2.0, (double)len) - 1.0), x, y, w; int count = 0, i1, i2, num = 0; printf("第 %d 世代\n", gen); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 0) { num++; printf("%3d ", num); x = 0.0; w = 0.0; for (i2 = len-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += pow(2.0, w); w += 1.0; } x *= cv; y = 0.0; w = 0.0; for (i2 = 2*len-1; i2 >= len; i2--) { if (ind[i1][i2] > 0) y += pow(2.0, w); w += 1.0; } y *= cv; printf("%8.5f %8.5f", x, y); if (pi_w[i1] > 1) printf(" 適応度 %8.5f\n", pi[i1]); else printf("\n"); count++; if (count == out) { count = 0; getchar(); } } } if (count > 0) getchar(); } /**************/ /* 親のコピー */ /**************/ void Species::C_copy() { int i1, i2, k, p, p1, p2, sw; // 親の選択 p1 = select(); sw = 0; while (sw == 0) { p2 = select(); if (p1 != p2) sw = 1; } // コピー for (i1 = 0; i1 < 2; i1++) { p = (i1 == 0) ? p1 : p2; k = position(); pi_w[k] = 1; for (i2 = 0; i2 < 2*len; i2++) ind[k][i2] = ind[p][i2]; } } /*******************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば,*/ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* pair : 親のペア数(default=最大子供数/2) */ /* pr : 交叉確率(default=1.0) */ /*******************************************************/ void Species::C_unifm(int pair, double pr) { int i1, i2, k1, k2, p1, p2, sw; /* 初期設定 */ if (pair == 0) pair = max_ch / 2; /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > pr) C_copy(); // 交叉する場合 else { // 親の選択と子供を入れる場所 p1 = select(); sw = 0; while (sw == 0) { p2 = select(); if (p1 != p2) sw = 1; } k1 = position(); pi_w[k1] = 1; k2 = position(); pi_w[k2] = 1; // 交叉 for (i2 = 0; i2 < 2*len; i2++) { if (genrand_real3() > 0.5) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } else { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ void Species::M_alle(double pr) { int i1, i2; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < 2*len; i2++) { if (genrand_real3() <= pr) ind[i1][i2] = (genrand_real3() > 0.5) ? 1 : 0; } } } } /************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=2) */ /************************************************/ void Species::S_roul(int elite) { int i1, i2, i3, k = 0, max, n = 0, p, sw; /* 初期設定 */ for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; /* 重複個体を削除 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 0) { for (i2 = i1+1; i2 < size+max_ch; i2++) { if (pi_w[i2] > 0) { sw = 0; for (i3 = 0; i3 < 2*len && sw == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw = 1; } if (sw == 0) pi_w[i2] = 0; } } } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) n++; } if (n == 0) { printf("***error 残す個体がない (S_roul)\n"); exit(1); } /* 淘汰して残す個体を選ぶ */ // エリートの選択 sw = 0; while (k < elite && k < n && sw == 0) { max = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1 && s_w[i1] == 0) { if (max < 0 || pi[i1] > pi[max]) max = i1; } } if (max < 0) sw = 1; else { s_w[max] = 1; k++; } } // ルーレット選択 int count = 0; while (count < size+max_ch && k < size && k < n) { p = select(); if (s_w[p] > 0) { sw = 1; count++; } else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (k < size && k < n) { for (i1 = 0; i1 < size+max_ch && k < size && k < n; i1++) { if (pi_w[i1] > 1 && s_w[i1] == 0) { s_w[i1] = 1; k++; } } } // 複数回選択されたものの処理 for (i1 = 0; i1 < size+max_ch; i1++) { if (s_w[i1] == 0) pi_w[i1] = 0; } for (i1 = 0; i1 < size+max_ch; i1++) { if (s_w[i1] > 0) { if (s_w[i1] > 1) { for (i2 = 2; i2 <= s_w[i1]; i2++) { k = position(); pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < 2*len; i3++) ind[k][i3] = ind[i1][i3]; } } } } } /************************/ /* 空いている場所を探す */ /************************/ int Species::position() { int i1, k = -1; for (i1 = 0; i1 < size+max_ch && k < 0; i1++) { if (pi_w[i1] == 0) k = i1; } if (k < 0) { printf("***error 空いている場所がない --position--\n"); exit(1); } return k; } /**************/ /* 個体の選択 */ /**************/ int Species::select() { double sum, x; int i1, k, n = 0, sw; /* ルーレット版の用意 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) n++; } sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } sum = 0.0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += ro[i1]; ro[i1] = sum; } } /* 選択 */ x = genrand_real3(); sw = 0; k = 0; for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] > 1) { if (x <= ro[i1]) { sw = 1; k = i1; } } } return k; }
世代交代数 1000 乱数の初期値 12345 関数 1 出力 100 個体数 20 子供の数 20 遺伝子長 20 エリート 2 突然変異率 0.03