データ例,プログラム
-------------------------i_data------------------------- 世代交代数 3000 乱数の初期値 123 関数 1 出力 300 個体数 20 子供の数 20 遺伝子長 20 エリート 2 突然変異率 0.03 -------------------------program------------------------- /****************************/ /* 2変数関数の最小値 */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.util.StringTokenizer; import java.util.Random; public class Test { public static void main(String args[]) throws IOException { double mute; int fun, gen, max_gen, o_lvl, seed, size, child, len, elite; String str; StringTokenizer dt; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // データの入力 str = in.readLine(); dt = new StringTokenizer(str, " "); dt.nextToken(); max_gen = Integer.parseInt(dt.nextToken()); dt.nextToken(); seed = Integer.parseInt(dt.nextToken()); dt.nextToken(); fun = Integer.parseInt(dt.nextToken()); dt.nextToken(); o_lvl = Integer.parseInt(dt.nextToken()); str = in.readLine(); dt = new StringTokenizer(str, " "); dt.nextToken(); size = Integer.parseInt(dt.nextToken()); dt.nextToken(); child = Integer.parseInt(dt.nextToken()); dt.nextToken(); len = Integer.parseInt(dt.nextToken()); str = in.readLine(); dt = new StringTokenizer(str, " "); dt.nextToken(); elite = Integer.parseInt(dt.nextToken()); dt.nextToken(); mute = Double.parseDouble(dt.nextToken()); // 種の定義 Species a = new Species(size, child, len, seed); // 初期設定 gen = 0; a.I_std(); // 個体の評価 a.Adap(fun); // 初期世代の出力 if (o_lvl > 0) a.O_std(gen, 20); // 実行 for (gen = 1; gen <= max_gen; gen++) { // 交叉 a.C_unifm(0, 1.0); // 突然変異 a.M_alle(mute); // 適応度の計算 a.Adap(fun); // 淘汰 a.S_roul(elite); // 出力 if (o_lvl > 0 && gen%o_lvl == 0) a.O_std(gen, 20); } // 最終出力 if (o_lvl == 0) a.O_std(gen-1, size+1); } } /*************************/ /* クラス Species の定義 */ /*************************/ class Species { private double pi[]; // 適応度 private double ro[]; // ルーレット板 private int size; // 個体総数 private int max_ch; // 子供の数の最大値 private int len; // 遺伝子長 private byte ind[][]; // 集団(個体の集まり) private byte pi_w[]; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) private byte s_w[]; // 淘汰用指標(選択された回数) private Random rn; // 乱数 /****************************/ /* コンストラクタ */ /* s : 個体総数 */ /* mc : 子供の数 */ /* mx : 遺伝子長 */ /* seed : 乱数の初期値 */ /****************************/ Species(int s, int mc, int mx, int seed) { int i1, num; /* 乱数の初期設定 */ rn = new Random(seed); /* 値の設定 */ size = s; max_ch = mc; len = mx; /* 領域の確保 */ num = size + max_ch; ind = new byte [num][2*len]; pi = new double [num]; pi_w = new byte [num]; s_w = new byte [num]; ro = new double [num]; } /*********************************/ /* 標準出力 */ /* gen : 現在の世代 */ /* out : n>0 : n個ずつ出力 */ /*********************************/ void O_std(int gen, int out) { double cv = 5.0 / (Math.pow(2.0, (double)len) - 1.0), x, y, w; int count = 0, i1, i2, num = 0; System.out.println("第 " + gen + " 世代"); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 0) { num++; System.out.print(num + " "); x = 0.0; w = 0.0; for (i2 = len-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += Math.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 += Math.pow(2.0, w); w += 1.0; } y *= cv; System.out.print(x + " " + y); if (pi_w[i1] > 1) System.out.println(" 適応度 " + pi[i1]); else System.out.println(); count++; if (count == out) count = 0; } } } /************/ /* 初期設定 */ /************/ void 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] = (rn.nextDouble() > 0.5) ? (byte)1 : (byte)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; } } } } /**************/ /* 親のコピー */ /**************/ void C_copy() { int i1, i2, k, p, p1, p2 = 0, 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 : 親のペア数 */ /* pr : 交叉確率 */ /*******************************************************/ void C_unifm(int pair, double pr) { int i1, i2, k1, k2, p1, p2 = 0, sw; /* 初期設定 */ if (pair == 0) pair = max_ch / 2; /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > 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 (rn.nextDouble() > 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 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 (rn.nextDouble() <= pr) ind[i1][i2] = (rn.nextDouble() > 0.5) ? (byte)1 : (byte)0; } } } } /*************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数 */ /*************************************/ void 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) { System.out.println("***error 残す個体がない (S_roul)"); System.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]; } } } } } /************************/ /* 適応度の計算 */ /* sw : 関数の種類 */ /************************/ double Adap(int sw) { double cv = 5.0 / (Math.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 += Math.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 += Math.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; } /************************/ /* 空いている場所を探す */ /************************/ int 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) { System.out.println("***error 空いている場所がない --position--"); System.exit(1); } return k; } /**************/ /* 個体の選択 */ /**************/ int 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 = rn.nextDouble(); 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