情報学部 | 菅沼ホーム | 目次 | 索引 |
/***********************************/ /* 遺伝的アルゴリズムによるTSPの解 */ /* coded by Y.Suganuma */ /***********************************/ /***********************/ /* クラスSpeciesの定義 */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include "MT.h" class Species { protected: double max; // 最大適応度 double mean; // 平均適応度 double *pi; // 適応度 double *ro; // ルーレット板 int allele_u; // 対立遺伝子上限 int allele_l; // 対立遺伝子下限 int size; // 個体総数 int max_ch; // 子供の数の最大値 int max_len; // 最大遺伝子長 int min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) int max_n; // 最大適応度の個体番号 int dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す int dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す int **ind; // 集団(個体の集まり) int *len; // 各個体の遺伝子長 int *kou1; // 交叉・突然変異用作業場所1 int *kou2; // 交叉・突然変異用作業場所2 int *s_w; // 淘汰用指標(選択された回数) int **edge; // エッジ組み替え交叉用ワークエリア char *pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) int Position(int); int Select(int method=-1, double bias=0.0, double step=1.0); public: // コンストラクタ Species(char *, long); // デストラクタ ~Species(); // 標準的な初期設定 void Init_std(); // 標準的な出力 void Out_std(int, int, int, char *); // 交叉 // 親のコピー void C_copy(int method=2, int pair=0, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 多点交叉 void C_point(double, int k_point=1, int k_vr=0, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 一様交叉 void C_uniform(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 平均化交叉 void C_mean(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 循環交叉 void C_cycle(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 部分的交叉 void C_part(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 順序交叉 void C_seq(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 一様順序交叉 void C_useq(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 一様位置交叉 void C_upos(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // エッジ組み替え交叉 void C_edge(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // サブツアー交叉 void C_sub(double, int count=10); // 突然変異 // 対立遺伝子への置換 void M_alle(double); // 移動 void M_move(double); // 逆位 void M_inv(double, int wd=0); // スクランブル void M_scram(double pr, int wd=0); // 転座 void M_chg(double pr, int wd=0); // 重複 void M_dup(double pr, int wd=0); // 摂動 void M_per(double pr, int method=0, double m=0.0, double s=1.0); // 挿入 void M_ins(double pr, int wd=0); // 削除 void M_del(double pr, int wd=0); // エリート・ルーレット選択 void S_roul(int elite=0, int s_method=1, double s_bias=0.0, double s_step=1.0); }; double norm_d(double, double); /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ Species::Species(char *name, long seed) { int i1, kind, num; FILE *in; /* データの入力 */ in = fopen(name, "r"); fscanf(in,"%*s %d %*s %d", &allele_u, &allele_l); fscanf(in,"%*s %d %*s %d", &max_len, &min_len); fscanf(in,"%*s %d %*s %d", &dup_a, &dup_s); fscanf(in,"%*s %d %*s %d", &size, &max_ch); /* データのチェック */ if (size <= 0) { printf("***error 個体総数≦0 (Constructor)\n"); exit(1); } if (max_ch < 0) { printf("***error 子供の数<0 (Constructor)\n"); exit(1); } if (max_len <= 0 || min_len == 0) { printf("***error 遺伝子長≦0 (Constructor)\n"); exit(1); } if (max_len < min_len) { printf("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n"); exit(1); } if (allele_u <= allele_l) { printf("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n"); exit(1); } kind = allele_u - allele_l + 1; if (dup_a == 0 && max_len > kind) { printf("***error 遺伝子の重複を防ぐことはできない (Constructor)\n"); exit(1); } /* 領域の確保 */ num = size + max_ch; ind = new int * [num]; for (i1 = 0; i1 < num; i1++) ind[i1] = new int [max_len]; edge = new int * [max_len]; for (i1 = 0; i1 < max_len; i1++) edge[i1] = new int [5]; pi = new double [num]; ro = new double [num]; len = new int [num]; kou1 = new int [max_len]; kou2 = new int [max_len]; s_w = new int [num]; pi_w = new char [num]; /* 乱数の初期設定 */ init_genrand(seed); } /****************/ /* デストラクタ */ /****************/ Species::~Species() { int i1; for (i1 = 0; i1 < size+max_ch; i1++) delete [] ind[i1]; delete [] ind; for (i1 = 0; i1 < max_len; i1++) delete [] edge[i1]; delete [] edge; delete [] pi; delete [] len; delete [] kou1; delete [] kou2; delete [] pi_w; delete [] s_w; delete [] ro; } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ int Species::Position(int n) { int i1, k = -1, sw = 0; /* 空いている場所を探す */ if (n < 0) { 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); } } /* n番目の親(pi_w[i]=2)を捜す */ else { for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] == 2) { k++; if (k == n) { sw = 1; k = i1; } } } } return k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値(default=0) */ /* step : β(default=1) */ /* return : 個体番号 */ /*******************************************************************/ int Species::Select(int method, double bias, double step) { double sum = 0.0, x; int i1, k, min, n, sw; // ルーレット板の用意 switch (method) { // ランダム case -1: n = 0; 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; } break; // 評価値をそのまま利用 case 0: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += pi[i1]; n++; } } if (fabs(sum) > 1.0e-10) { sum = 1.0 / fabs(sum); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = pi[i1] * sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 最小値からの差 case 1: min = -1; n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { n++; if (min < 0 || pi[i1] < pi[min]) min = i1; } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = pi[i1] - pi[min]; if (ro[i1] < bias) ro[i1] = bias; sum += ro[i1]; } } if (sum > 1.0e-10) { sum = 1.0 / sum; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 線形化 case 2: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = -1.0; n++; } else ro[i1] = 1.0; } sw = 0; sum = bias; while (sw == 0) { min = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (ro[i1] < 0.0 && (min < 0 || pi[i1] < pi[min])) min = i1; } if (min < 0) sw = 1; else { ro[min] = sum; sum += step; } } sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } break; } 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; } /********************/ /* 標準的な初期設定 */ /********************/ void Species::Init_std() { int i1, i2, i3, length, lid, 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) { // 遺伝子長の決定 if (min_len < 0) length = max_len; else { length = (int)(genrand_real3() * (max_len - min_len + 1) + min_len); if (length > max_len) length = max_len; } len[i1] = length; // 遺伝子の決定 for (i2 = 0; i2 < length; i2++) { sw2 = 0; while (sw2 == 0) { lid = (int)(genrand_real3() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; ind[i1][i2] = lid; // 重複遺伝子のチェック sw2 = 1; if (dup_a == 0) { for (i3 = 0; i3 < i2 && sw2 > 0; i3++) { if (lid == ind[i1][i3]) sw2 = 0; } } } } // 重複個体のチェック sw1 = 1; if (dup_s == 0) { for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { if (len[i1] == len[i2]) { sw2 = 0; for (i3 = 0; i3 < len[i1] && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ void Species::Out_std(int sw, int out_m, int gen, char *name) { int i1, i2, k = 0, pr; char *now; time_t aclock; FILE *out; if (sw >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); scanf("%d", &pr); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) { out = stdout; getchar(); } else { time(&aclock); now = ctime(&aclock); out = fopen(name, "a"); fprintf(out, "***世代 %d 適応度 max %f (%d) mean %f 時間 %s\n", gen, max, max_n, mean, now); } // 詳細出力 for (i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { fprintf(out, "%d allele", i1); for (i2 = 0; i2 < len[i1]; i2++) fprintf(out, " %d", ind[i1][i2]); fprintf(out, " value %f\n", pi[i1]); if (pr > 0) { k++; if (k == pr) { getchar(); k = 0; } } } } if (pr < 0) fclose(out); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供)(default) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数(default=max_ch/2) */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_copy(int method, int pair, int k_method, double k_bias, double k_step) { int i1, i2, i3, k, p, p1, p2, sw; /* 初期設定とデータチェック */ if (method != 1) method = 2; if (pair <= 0) pair = (method==2) ? max_ch/2 : max_ch; else { if (method == 2 && 2*pair > max_ch || method == 1 && pair > max_ch) { printf("***error 子供が多すぎる (C_copy)\n"); exit(1); } } /* 実行 */ for (i1 = 0; i1 < pair; i1++) { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // コピー for (i2 = 0; i2 < method; i2++) { p = (i2 == 0) ? p1 : p2; k = Position(-1); len[k] = len[p]; pi_w[k] = 1; for (i3 = 0; i3 < len[k]; i3++) ind[k][i3] = ind[p][i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数(default=1) */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉(default) */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_point(double kosa, int k_point, int k_vr, int k_method, double k_bias, double k_step) { int abs_p, c1, c2, i1, i2, i3, k1, k2, mn = 0, num, p1, p2, pair, sw, t11, t12, t21, t22; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { printf("***error 交叉方法が不適当 (C_point)\n"); exit(1); } abs_p = abs(k_point); if (abs_p == 0 || abs_p > max_len-1 || min_len > 0 && abs_p > min_len-1) { printf("***error 交叉点の数が不適当 (C_point)\n"); exit(1); } if (k_vr > 0 && min_len < 0) { printf("***error 遺伝子長は可変でなければならない (C_point)\n"); exit(1); } /* 交叉 */ num = k_point; for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 交叉位置の数の決定 if (k_point < 0) { num = (int)(genrand_real3() * abs_p + 1); if (num > abs_p) num = abs_p; } // 交叉位置の決定(点の後ろで交叉) for (i2 = 0; i2 < num; i2++) { // 親1の交叉位置 sw = 0; while (sw == 0) { sw = 1; kou1[i2] = (int)(genrand_real3() * (len[p1] - 1)); if (kou1[i2] > len[p1]-2) kou1[i2] = len[p1] - 2; if (k_vr == 0 && kou1[i2] > len[p2]-2) kou1[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou1[i3] == kou1[i2]) sw = 0; } } // 親2の交叉位置 if (k_vr > 0) { sw = 0; while (sw == 0) { sw = 1; kou2[i2] = (int)(genrand_real3() * (len[p2] - 1)); if (kou2[i2] > len[p2]-2) kou2[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou2[i3] == kou2[i2]) sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ c1 = 0; c2 = 0; t11 = 0; t21 = 0; // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; for (i2 = 0; i2 < num+1; i2++ ) { // 次の交叉位置を求める if (i2 == num) { // 最後 t12 = len[p1]; t22 = len[p2]; } else { // 親1 t12 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou1[i3] >= 0 && kou1[i3] <= t12) { t12 = kou1[i3]; mn = i3; } } kou1[mn] = -1; t12++; // 親2 if (k_vr == 0) t22 = t12; else { t22 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou2[i3] >= 0 && kou2[i3] <= t22) { t22 = kou2[i3]; mn = i3; } } kou2[mn] = -1; t22++; } } // 指定箇所のコピー for (i3 = t11; i3 < t12; i3++) { if (i2%2 == 0) { if (c1 < max_len) { ind[k1][c1] = ind[p1][i3]; c1++; } } else { if (c2 < max_len) { ind[k2][c2] = ind[p1][i3]; c2++; } } } for (i3 = t21; i3 < t22; i3++) { if (i2%2 == 0) { if (c2 < max_len) { ind[k2][c2] = ind[p2][i3]; c2++; } } else { if (c1 < max_len) { ind[k1][c1] = ind[p2][i3]; c1++; } } } // 交叉位置の移動 t11 = t12; t21 = t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_uniform(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k1, k2, p1, p2, pair, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { printf("***error 交叉方法が不適当 (C_uniform)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_uniform)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; 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]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_mean(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k, p1, p2, sw; /* 初期設定とデータのチェック */ if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_mean)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < max_ch; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(1, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); len[k] = len[p1]; pi_w[k] = 1; // 交叉 for (i2 = 0; i2 < len[k]; i2++) ind[k][i2] = (ind[p1][i2] + ind[p2][i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_cycle(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_cycle)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_cycle)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 初期設定 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = 0; kou2[i2] = 0; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 sw = 0; while (sw == 0) { sw = 1; p = (int)(genrand_real3() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; if (kou1[p] == 0 && kou2[p] == 0) { kou1[p] = 1; kou2[p] = 1; ind[k1][p] = ind[p1][p]; ind[k2][p] = ind[p2][p]; for (i2 = 0; i2 < len[p1] && sw > 0; i2++) { if (ind[p2][p] == ind[p1][i2]) { ind[k1][i2] = ind[p1][i2]; kou1[i2] = 1; sw = 0; } } sw = 1; for (i2 = 0; i2 < len[p2] && sw > 0; i2++) { if (ind[p1][p] == ind[p2][i2]) { ind[k2][i2] = ind[p2][i2]; kou2[i2] = 1; sw = 0; } } } } sw = 0; i2 = 0; i3 = 0; while (sw == 0) { while (sw == 0 && i2 < len[p1]) { if (kou1[i2] == 0) sw = 1; else i2++; } sw = 0; while (sw == 0 && i3 < len[p2]) { if (kou2[i3] == 0) sw = 1; else i3++; } if (i2 < len[p1] && i3 < len[p2]) { ind[k1][i2] = ind[p2][i3]; ind[k2][i3] = ind[p1][i2]; sw = 0; i2++; i3++; } else sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_part(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, lv, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_part)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_part)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(genrand_real3() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } for (i2 = p; i2 < len[p1]; i2++) { sw = 0; lv = ind[k1][i2]; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (ind[k2][i2] == ind[k1][i3]) { ind[k1][i2] = ind[k1][i3]; ind[k1][i3] = lv; sw = 1; } } sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (lv == ind[k2][i3]) { ind[k2][i3] = ind[k2][i2]; ind[k2][i2] = lv; sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_seq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, pp, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_seq)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_seq)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(genrand_real3() * (len[p1] - 1)); if (p >= len[p1]-1) p = len[p1] - 2; for (i2 = 0; i2 <= p; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } pp = 0; for (i2 = p+1; i2 < len[p1]; i2++) { sw = 0; for (i3 = pp; i3 < len[p2] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4]) { sw = 1; pp = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } pp = 0; for (i2 = p+1; i2 < len[p2]; i2++) { sw = 0; for (i3 = pp; i3 < len[p1] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4]) { sw = 1; pp = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_useq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_useq)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_useq)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; kou1[i2] = (genrand_real3() < 0.5) ? 0 : 1; } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p2] && sw == 0; i3++) { for (i4 = 0; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p1] && sw == 0; i3++) { for (i4 = 0; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_upos(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_upos)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_upos)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = (genrand_real3() < 0.5) ? 0 : 1; if (kou1[i2] > 0) { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p1][i2] == ind[k1][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k1][i3] = ind[p1][i2]; p = i3 + 1; sw = 1; } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { sw = 0; for (i3 = 0; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p2][i2] == ind[k2][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k2][i3] = ind[p2][i2]; p = i3 + 1; sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_edge(double kosa, int k_method, double k_bias, double k_step) { int e[2], i1, i2, i3, i4, i5, k, kk, k0 = 0, k1, k2, min, num, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_edge)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_edge)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(1, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); pi_w[k] = 1; len[k] = len[p1]; // エッジマップの初期化 for (i2 = 0; i2 < len[k]; i2++) { edge[i2][0] = 0; for (i3 = 1; i3 <= 4; i3++) edge[i2][i3] = -1; } // 交叉 // エッジマップの作成 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p1][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p1][len[k]-1]; e[1] = ind[p1][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p1][i3-1]; e[1] = ind[p1][0]; } else { e[0] = ind[p1][i3-1]; e[1] = ind[p1][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p2][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p2][len[k]-1]; e[1] = ind[p2][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p2][i3-1]; e[1] = ind[p2][0]; } else { e[0] = ind[p2][i3-1]; e[1] = ind[p2][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { sw = 1; for (i5 = 1; i5 <= edge[i2][0] && sw == 1; i5++) { if (edge[i2][i5] == e[i4]) sw = 2; } if (sw == 1) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } } } // 交叉の実行 // 出発点の決定 k1 = ind[p1][0]; k2 = ind[p2][0]; if (edge[k1][0] == edge[k2][0]) kk = (genrand_real3() > 0.5) ? k2 : k1; else kk = (edge[k1][0] < edge[k2][0]) ? k1 : k2; ind[k][0] = kk; p = 1; while (p < len[k]) { // ノードの除去 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; if (edge[i2][0] > 0) { for (i3 = 1; i3 <= 4 && sw == 0; i3++) { if (edge[i2][i3] == kk) { sw = 1; edge[i2][i3] = -1; edge[i2][0]--; } } } } // 次の現在ノードの選択 min = 10; num = 0; for (i2 = 1; i2 <= 4; i2++) { if (edge[kk][i2] >= 0) { k1 = edge[kk][i2]; if (edge[k1][0] >= 0 && edge[k1][0] < min) { num = 1; min = edge[k1][0]; k0 = k1; } else { if (edge[k1][0] == min) num++; } } } if (num > 1) { k1 = (int)(genrand_real3() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 1; i2 <= 4 && k0 < 0; i2++) { if (edge[kk][i2] >= 0) { if (edge[edge[kk][i2]][0] == min) { k2++; if (k1 == k2) k0 = edge[kk][i2]; } } } } else { if (num <= 0) { num = 0; for (i2 = 0; i2 < len[k]; i2++) { if (i2 != kk && edge[i2][0] >= 0) num++; } if (num <= 0) { printf("***error invalid data (C_edge)\n"); exit(1); } else { k1 = (int)(genrand_real3() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 0; i2 < len[k] && k0 < 0; i2++) { if (i2 != kk && edge[i2][0] >= 0) { k2++; if (k1 == k2) k0 = i2; } } } } } edge[kk][0] = -1; ind[k][p] = k0; kk = k0; p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数(default=10) */ /*************************************************************/ void Species::C_sub(double kosa, int count) { int i1, i2, i3, i4, i5, k1, k2, k3, k4, p1, p2, t11, t12, t21, t22 = 0, sw; /* 初期設定とデータのチェック */ if ((4*count*size*(size-1)) > max_ch) { printf("***error 子供が多すぎる (C_sub)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < size-1; i1++) { // 親1 p1 = Position(i1); if (p1 >= 0) { for (i2 = i1; i2 < size; i2++) { // 親2 p2 = Position(i2); if (p2 >= 0) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 交叉回数の制御 for (i3 = 0; i3 < count; i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 t11 = (int)(genrand_real3() * len[p1]); if (t11 > (len[p1]-1)) t11 = len[p1] - 1; sw = 0; while (sw == 0) { t12 = (int)(genrand_real3() * len[p1]); if (t12 > (len[p1]-1)) t12 = len[p1] - 1; if (t12 != t11) sw = 1; } if (t11 > t12) { k1 = t11; t11 = t12; t12 = k1; } // 親2の交叉位置 sw = 0; t21 = -1; for (i4 = 0; i4 < len[p2] && t21 < 0; i4++) { for (i5 = t11; i5 <= t12 && t21 < 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) t21 = i4; } } if (t21 >= 0) { t22 = t21 + t12 - t11; if (t22 < len[p2]) { sw = 1; for (i4 = t21+1; i4 <= t22 && sw > 0; i4++) { sw = 0; for (i5 = t11; i5 <= t12 && sw == 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) sw = 1; } } } } // 交叉の実行 if (sw > 0) { k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p1]; k3 = Position(-1); pi_w[k3] = 1; len[k3] = len[p2]; k4 = Position(-1); pi_w[k4] = 1; len[k4] = len[p2]; for (i4 = 0; i4 < t11; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = t11; i4 <= t12; i4++) { ind[k1][i4] = ind[p2][t21+i4-t11]; ind[k2][i4] = ind[p2][t22-i4+t11]; } for (i4 = t12+1; i4 < len[p1]; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = 0; i4 < t21; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } for (i4 = t21; i4 <= t22; i4++) { ind[k3][i4] = ind[p1][t11+i4-t21]; ind[k4][i4] = ind[p1][t12-i4+t21]; } for (i4 = t22+1; i4 < len[p2]; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ void Species::M_alle(double pr) { int i1, i2, lid; /* データのチェックと初期設定 */ if (dup_a == 0) { printf("***error 突然変異方法が不適当 (M_alle)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (genrand_real3() <= pr) { lid = (int)(genrand_real3() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; if (lid != ind[i1][i2]) ind[i1][i2] = lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ void Species::M_move(double pr) { int i1, i2, ld, p1, p2, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 位置の決定 */ // p1 p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p2 sw = 0; while (sw == 0) { p2 = (int)(genrand_real3() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } /* 実行 */ if (p2 > p1) { ld = ind[i1][p2]; for (i2 = p2; i2 > p1; i2--) ind[i1][i2] = ind[i1][i2-1]; ind[i1][p1] = ld; } else { ld = ind[i1][p2]; for (i2 = p2; i2 < p1-1; i2++) ind[i1][i2] = ind[i1][i2+1]; ind[i1][p1-1] = ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /********************************************************/ void Species::M_inv(double pr, int wd) { int i1, lid, p, p1, p2, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(genrand_real3() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(genrand_real3() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ sw = 0; while (sw == 0) { lid = ind[i1][p1]; ind[i1][p1] = ind[i1][p2]; ind[i1][p2] = lid; p1++; p2--; if (p1 >= p2) sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_scram(double pr, int wd) { int i1, i2, ld, p, p1, p2, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(genrand_real3() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(genrand_real3() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ for (i2 = p1; i2 <= p2; i2++) { p = (int)(genrand_real3() * (p2 - p1 + 1) + p1); if (p > p2) p = p2; ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_chg(double pr, int wd) { int i1, i2, ld, p, p1, p2, p3, p4, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 区間等の決定([p1,p2]と[p3,p4]の入れ替え) */ // p1 p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(genrand_real3() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 小さい方をp1,p2にする if (p1 > p3) { p = p1; p1 = p3; p3 = p; } // p4, p2 p4 = (wd == 0) ? (int)(genrand_real3() * (len[i1] - p3)) + p3 : p1 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); // 重複部分のチェック if (p2 >= p3) { p = p3 - 1; p3 = p2 + 1; p2 = p; p4 = p3 + (p2 - p1); } /* 実行 */ p = p3; for (i2 = p1; i2 <= p2; i2++) { ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(deafult) */ /**********************************************************************/ void Species::M_dup(double pr, int wd) { int i1, i2, p, p1, p2, p3, p4, sw; /* データのチェック */ if (dup_a == 0) { printf("***error 突然変異方法が不適当 (M_dup)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(genrand_real3() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 区間を決める if (p3 > p1) { p4 = (wd == 0) ? (int)(genrand_real3() * (len[i1] - p3)) + p3 : p3 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); } else { p2 = (wd == 0) ? (int)(genrand_real3() * (len[i1] - p1)) + p1 : p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; p4 = p3 + (p2 - p1); } // 実行 p = p4; for (i2 = p2; i2 >= p1; i2--) { ind[i1][p] = ind[i1][i2]; p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布(default) */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限(default=0.0) */ /* s : 標準偏差または一様分布の上限(default=1.0) */ /******************************************************/ void Species::M_per(double pr, int method, double m, double s) { double w, wd = 0.0, x1; int i1, i2; /* データのチェックと初期設定 */ if (dup_a == 0) { printf("***error 突然変異方法が不適当 (M_per)\n"); exit(1); } if (method > 0) wd = s - m; /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (genrand_real3() <= pr) { if (method == 0) w = norm_d(m, s); else { w = genrand_real3() * wd; if (genrand_real3() < 0.5) w = -w; } x1 = (double)ind[i1][i2] + w; if (x1 > allele_u) x1 = allele_u; else { if (x1 < allele_l) x1 = allele_l; } ind[i1][i2] = (int)x1; } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_ins(double pr, int wd) { int i1, i2, l, ld, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { printf("***error 突然変異方法が不適当 (M_ins)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { // 挿入位置の決定 p = (int)(genrand_real3() * (len[i1]+1)); if (p > len[i1]) p = len[i1]; // 挿入する遺伝子長の決定 l = (wd == 0) ? (int)(genrand_real3() * (max_len - len[i1] + 1)) : wd; if (l > max_len-len[i1]) l = max_len - len[i1]; else { if (l <= 0) l = 1; } // 実行 // 挿入場所の確保 if (p < len[i1]) { for (i2 = len[i1]+l-1; i2 >= p; i2--) ind[i1][i2] = ind[i1][i2-l]; } // 挿入場所の遺伝子の決定 for (i2 = p; i2 < p+l; i2++) { ld = (int)(genrand_real3() * (allele_u - allele_l + 1) + allele_l); if (ld > allele_u) ld = allele_u; ind[i1][i2] = ld; } len[i1] += l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_del(double pr, int wd) { int i1, i2, l, max, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { printf("***error 突然変異方法が不適当 (M_del)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { // 削除位置の決定 p = (int)(genrand_real3() * len[i1]); if (p >= len[i1]) p = len[i1] - 1; // 削除する遺伝子長の決定 max = (len[i1]-min_len < len[i1]-p) ? len[i1] - min_len : len[i1] - p; l = (wd == 0) ? (int)(genrand_real3() * max + 1) : wd; if (l > max) l = max; // 実行 for (i2 = 0; i2 < len[i1]-p-l; i2++) ind[i1][p+i2] = ind[i1][p+i2+l]; len[i1] -= l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ void Species::S_roul(int elite, int s_method, double s_bias, double s_step) { int count = 0, i1, i2, i3, k = 0, max, n = 0, p, sw; /* 値のチェックと初期設定 */ if (s_method != 0 && s_method != 2) s_method = 1; if (elite > size) { printf("***error エリートで残す数が多すぎる (S_roul)\n"); exit(1); } if (s_method == 2 && s_step <= 0.0) s_step = 1.0; for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; /* 重複個体を削除 */ if (dup_s == 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 && len[i1] == len[i2]) { sw = 0; for (i3 = 0; i3 < len[i1] && 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 || dup_s == 0 && n < size) { 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++; } } // ルーレット選択 while (count < size+max_ch && k < size) { p = Select(s_method, s_bias, s_step); if (dup_s == 0 && s_w[p] > 0) count++; else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (dup_s == 0 && k < size) { for (i1 = 0; i1 < size+max_ch && k < size; 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(-1); len[k] = len[i1]; pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < len[i1]; i3++) ind[k][i3] = ind[i1][i3]; } } } } } /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ double norm_d(double m, double s) { double x = 0.0; int i1; for (i1 = 0; i1 < 12; i1++) x += genrand_real3(); x = s * (x - 6.0) + m; return x; } /*******************/ /* クラスTSPの定義 */ /*******************/ class TSP : public Species { int max_gen; // 最大世代交代数 int kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 循環交叉 // =2 : 部分的交叉 // =3 : 順序交叉 // =4 : 一様順序交叉 // =5 : 一様位置交叉 // =6 : エッジ組み替え交叉 // =7 : サブツアー交叉 double kosa; // 交叉確率 int k_point; // 交差点の数(負の時は,1から-k_point間のランダム) int k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) int k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double k_bias; // α,または,method=2の場合は初期値 double k_step; // β int mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 移動 // =1 : 逆位 // =2 : スクランブル // =3 : 転座 double mute; // 突然変異率 int wd; // 突然変異に使用する部分遺伝子長 double m_mean; // 摂動の平均値 double m_std; // 摂動の標準偏差 int elite; // エリート選択で残す数 int s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double s_bias; // α,または,s_method=2の場合は初期値 double s_step; // β int out_d; // 表示間隔 int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) int out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 char o_file[100]; // 出力ファイル名 int **city; //都市の位置データ int n_city; // 都市の数 int **rg; // 都市間の距離 int kinbo; // 近傍探索(0:行わない,1:行う) int neib; // 近傍(2 or 3) int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 public: // コンストラクタ TSP (char *, char *, long); // デストラクタ ~TSP (); // 全体の実行制御 void Control(); // 距離の計算 int Kyori(int, int*); // 適応度の計算 void Adap(); // 枝の入れ替え int Change(int, int *, int *); // 近傍の探索 void Kinbo(); // 出力 void Output(int); }; /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : TSP定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ TSP::TSP (char *name1, char *name2, long seed) : Species (name1, seed) { double x, y; int i1, i2; FILE *in; // 基本データの入力 in = fopen(name2, "r"); fscanf(in, "%*s %d %*s %d", &out_lvl, &out_m); fscanf(in, "%*s %s %*s %d", o_file, &out_d); fscanf(in, "%*s %d %*s %lf %*s %d %*s %d %*s %d %*s %lf %*s %lf", &kosa_m, &kosa, &k_point, &k_vr, &k_method, &k_bias, &k_step); fscanf(in, "%*s %d %*s %lf %*s %d %*s %lf %*s %lf", &mute_m, &mute, &wd, &m_mean, &m_std); fscanf(in, "%*s %d %*s %d %*s %lf %*s %lf", &elite, &s_method, &s_bias, &s_step); fscanf(in, "%*s %d %*s %d", &n_city, &max_gen); fscanf(in, "%*s %d %*s %d", &kinbo, &neib); fscanf(in, "%*s %d", &sel); if (kinbo > 0 && neib != 2 && neib != 3) { printf("***error 近傍の値が不適当 \n"); exit(1); } if (n_city != max_len) { printf("***error 都市数が不適当 \n"); exit(1); } // 都市の位置データ city = new int * [n_city]; for (i1 = 0; i1 < n_city; i1++) { city[i1] = new int [2]; fscanf(in, "%d %d", &city[i1][0], &city[i1][1]); } // 距離テーブル rg = new int * [n_city]; for (i1 = 0; i1 < n_city; i1++) { rg[i1] = new int [n_city]; for (i2 = i1+1; i2 < n_city; i2++) { x = city[i2][0] - city[i1][0]; y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(sqrt(x * x + y * y) + 0.5); } } for (i1 = 1; i1 < n_city; i1++) { for (i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } fclose(in); } /****************/ /* デストラクタ */ /****************/ TSP::~TSP() { int i1; for (i1 = 0; i1 < size+max_ch; i1++) delete [] ind[i1]; delete [] ind; for (i1 = 0; i1 < max_len; i1++) delete [] edge[i1]; delete [] edge; delete [] pi; delete [] len; delete [] kou1; delete [] kou2; delete [] pi_w; delete [] s_w; delete [] ro; for (i1 = 0; i1 < n_city; i1++) { delete [] city[i1]; delete [] rg[i1]; } delete [] city; delete [] rg; } /**************/ /* 全体の制御 */ /**************/ void TSP::Control() { int gen = 1, k1; // 初期集団の発生 Init_std(); // 評価 if (kinbo > 0) Kinbo(); else Adap(); // 出力 printf("***世代 %d 適応度 max %f (%d) mean %f\n", gen, max, max_n, mean); if (abs(out_lvl) > 0) Output(gen); // 世代交代 for (gen = 2; gen <= max_gen; gen++) { // 交叉 switch (kosa_m) { case -1: break; case 0: C_copy(); // 親のコピー break; case 1: C_cycle(kosa); // 循環交叉 break; case 2: C_part(kosa); // 部分的交叉 break; case 3: C_seq(kosa); // 順序交叉 break; case 4: C_useq(kosa); // 一様順序交叉 break; case 5: C_upos(kosa); // 一様位置交叉 break; case 6: C_edge(kosa); // エッジ組み替え交叉 break; case 7: C_sub(kosa, k_point); // サブツアー交叉 break; default: break; } // 突然変異 switch (mute_m) { case -1: break; case 0: M_move(mute); // 移動 break; case 1: M_inv(mute); // 逆位 break; case 2: M_scram(mute); // スクランブル break; case 3: M_chg(mute); // 転座 break; default: break; } // 適応度 if (kinbo > 0) Kinbo(); else Adap(); // 淘汰 S_roul(elite); // 出力 if (gen%out_d == 0) printf("***世代 %d 適応度 max %f (%d) mean %f\n", gen, max, max_n, mean); if (abs(out_lvl) > 0) { if (gen%abs(out_lvl) == 0) Output(gen); } } gen--; k1 = out_m; out_m = 0; printf("***世代 %d 適応度 max %f (%d) mean %f\n", gen, max, max_n, mean); Output(gen); out_m = k1; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* return : 距離(負) */ /*********************************/ int TSP::Kyori(int n_c, int *p) { int i1, n1, n2, range = 0; n1 = p[0]; for (i1 = 1; i1 < n_c; i1++) { n2 = p[i1]; range -= rg[n1][n2]; n1 = n2; } n2 = p[0]; range -= rg[n1][n2]; return range; } /****************/ /* 適応度の計算 */ /****************/ void TSP::Adap() { int i1, k = 0; mean = 0.0; max = 0.0; max_n = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { pi_w[i1] = 2; pi[i1] = Kyori(len[i1], ind[i1]); } if (pi_w[i1] > 0) { k++; mean += pi[i1]; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } if (k > 0) mean /= k; } /**************************************/ /* エッジの入れ替え */ /* n_city : 都市の数 */ /* seq : 訪問する順番 */ /* r_m : 距離の負値 */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ int TSP::Change(int n_city, int *seq, int *r_m) { int ch = 0, i1, i2, i3, i4, k, k1, k2, max, n1, n2, n3, nn, r, sw = 0; max = *r_m; n3 = (int)(genrand_real3() * (n_city - 2)); if (n3 > n_city-3) n3 = n_city - 3; // 2近傍 for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { if (n3 == 0) n1 = n_city - 2; else n1 = n_city - 1; for (i2 = n3+2; i2 <= n1 && ch == 0; i2++) { // 枝の場所((n3,n3+1), (k1,k2)) k1 = i2; if (i2 == n_city-1) k2 = 0; else k2 = i2 + 1; // 枝の入れ替え kou1[0] = seq[n3]; k = 1; for (i3 = k1; i3 >= n3+1; i3--) { kou1[k] = seq[i3]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価 r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } } n3++; if (n3 > n_city-3) n3 = 0; } // 3近傍 if (neib == 3 && ch == 0) { for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { n1 = n_city - 2; n2 = n_city - 1; for (i2 = n3+1; i2 <= n1 && ch == 0; i2++) { for (i3 = i2+1; i3 <= n2 && ch == 0; i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3; if (i3 == n_city-1) k2 = 0; else k2 = i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) kou1[0] = seq[n3]; k = 1; for (i4 = i2; i4 >= n3+1; i4--) { kou1[k] = seq[i4]; k++; } for (i4 = k1; i4 >= i2+1; i4--) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その1) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その2) kou1[0] = seq[n3]; k = 1; for (i4 = k1; i4 >= i2+1; i4--) { kou1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その2) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その3) kou1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { kou1[k] = seq[i4]; k++; } for (i4 = i2; i4 >= n3+1; i4--) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その3) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その4) kou1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { kou1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その4) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } } } n3++; if (n3 > n_city-3) n3 = 0; } } // 設定 if (sw > 0) { *r_m = max; for (i1 = 0; i1 < n_city; i1++) seq[i1] = kou2[i1]; } return sw; } /**************/ /* 近傍の探索 */ /**************/ void TSP::Kinbo() { int i1, k = 0, r, sw; max = 0.0; max_n = -1; mean = 0.0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { pi_w[i1] = 2; sw = 1; r = Kyori(len[i1], ind[i1]); while (sw > 0) sw = Change(len[i1], ind[i1], &r); pi[i1] = r; } if (pi_w[i1] > 0) { k++; mean += pi[i1]; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } if (k > 0) mean /= k; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ void TSP::Output(int gen) { int i1, k = 0, n, pr; char *now; time_t aclock; FILE *out; if (out_lvl >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); scanf("%d", &pr); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) { out = stdout; getchar(); } else { time(&aclock); now = ctime(&aclock); out = fopen(o_file, "a"); fprintf(out, "***世代 %d 適応度 max %f (%d) mean %f 時間 %s\n", gen, max, max_n, mean, now); } // 巡回順序の出力 if (out_m == 0) { for (i1 = 0; i1 < len[max_n]; i1++) { n = ind[max_n][i1]; fprintf(out, "%d %d %d\n", n, city[n][0], city[n][1]); if (pr > 0) { k++; if (k == pr) { getchar(); k = 0; } } } } if (pr < 0) fclose(out); } } /****************/ /* main program */ /****************/ int main(int argc, char *argv[]) { long *seed; int i1, n; char **i_file1, **i_file2; FILE *in; TSP *tsp; // 入力ミス if (argc <= 1) { printf("***error ファイル名を入力して下さい\n"); exit(1); } // 入力OK else { // ファイルのオープン in = fopen(argv[1], "r"); if (in == NULL) { printf("***error ファイル名が不適当です\n"); exit(1); } // 入力データファイル名の入力 fscanf(in, "%d", &n); // データの数 seed = new long [n]; i_file1 = new char * [n]; i_file2 = new char * [n]; for (i1 = 0; i1 < n; i1++) { i_file1[i1] = new char [100]; i_file2[i1] = new char [100]; seed[i1] = 1000 * i1 + 1234567; fscanf(in, "%s %s", i_file1[i1], i_file2[i1]); } fclose(in); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { printf("\n+++++ケース %d+++++\n", i1+1); tsp = new TSP (i_file1[i1], i_file2[i1], seed[i1]); tsp->Control(); } } return 0; } //----------------ケーススタディデータ(data_ct.txt)------ /* 3 data1_t.txt data2_t.txt data1_t.txt data2_t.txt data1_t.txt data2_t.txt */ //---------------Species記述データ(data1_t.txt)--------- /* 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 */ //---------------TSP記述データ(data2_t.txt)-------- /* 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ //---------------------MT.h--------------------------- // A C-program for MT19937, with initialization improved 2002/1/26. // Coded by Takuji Nishimura and Makoto Matsumoto. // // Before using, initialize the state by using init_genrand(seed) // or init_by_array(init_key, key_length). // // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The names of its contributors may not be used to endorse or promote // products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // // Any feedback is very welcome. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html // email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) // The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as // - delete line 47 "#include<stdio.h>" // - delete line 174 int main(void){...} // - change N -> MT_N // - change N -> MT_N // - change the file name "mt19937ar.c" -> "MT.h" /* // Period parameters #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits static unsigned long mt[MT_N]; // the array for the state vector static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized // initializes mt[MT_N] with a seed void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti<MT_N; mti++) { mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto mt[mti] &= 0xffffffffUL; // for >32 bit machines } } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (MT_N>key_length ? MT_N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; j++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } if (j>=key_length) j=0; } for (k=MT_N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } } mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array } // generates a random number on [0,0xffffffff]-interval unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; // mag01[x] = x * MATRIX_A for x=0,1 if (mti >= MT_N) { // generate N words at one time int kk; if (mti == MT_N+1) // if init_genrand() has not been called, init_genrand(5489UL); // a default initial seed is used for (kk=0;kk<MT_N-MT_M;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (;kk<MT_N-1;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } // generates a random number on [0,0x7fffffff]-interval long genrand_int31(void) { return (long)(genrand_int32()>>1); } // generates a random number on [0,1]-real-interval double genrand_real1(void) { return genrand_int32()*(1.0/4294967295.0); // divided by 2^32-1 } // generates a random number on [0,1)-real-interval double genrand_real2(void) { return genrand_int32()*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on (0,1)-real-interval double genrand_real3(void) { return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on [0,1) with 53-bit resolution double genrand_res53(void) { unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } // These real versions are due to Isaku Wada, 2002/01/09 added */
/********************************************************************/ /* f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 */ /* coded by Y.Suganuma */ /********************************************************************/ /***********************/ /* クラスSpeciesの定義 */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include "MT.h" class Species { protected: double max; // 最大適応度 double mean; // 平均適応度 double *pi; // 適応度 double *ro; // ルーレット板 int allele_u; // 対立遺伝子上限 int allele_l; // 対立遺伝子下限 int size; // 個体総数 int max_ch; // 子供の数の最大値 int max_len; // 最大遺伝子長 int min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) int max_n; // 最大適応度の個体番号 int dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す int dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す int **ind; // 集団(個体の集まり) int *len; // 各個体の遺伝子長 int *kou1; // 交叉・突然変異用作業場所1 int *kou2; // 交叉・突然変異用作業場所2 int *s_w; // 淘汰用指標(選択された回数) int **edge; // エッジ組み替え交叉用ワークエリア char *pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) int Position(int); int Select(int method=-1, double bias=0.0, double step=1.0); public: // コンストラクタ Species(char *, long); // デストラクタ ~Species(); // 標準的な初期設定 void Init_std(); // 標準的な出力 void Out_std(int, int, int, char *); // 交叉 // 親のコピー void C_copy(int method=2, int pair=0, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 多点交叉 void C_point(double, int k_point=1, int k_vr=0, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 一様交叉 void C_uniform(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 平均化交叉 void C_mean(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 循環交叉 void C_cycle(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 部分的交叉 void C_part(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 順序交叉 void C_seq(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 一様順序交叉 void C_useq(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // 一様位置交叉 void C_upos(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // エッジ組み替え交叉 void C_edge(double, int k_method=-1, double k_bias=0.0, double k_step=1.0); // サブツアー交叉 void C_sub(double, int count=10); // 突然変異 // 対立遺伝子への置換 void M_alle(double); // 移動 void M_move(double); // 逆位 void M_inv(double, int wd=0); // スクランブル void M_scram(double pr, int wd=0); // 転座 void M_chg(double pr, int wd=0); // 重複 void M_dup(double pr, int wd=0); // 摂動 void M_per(double pr, int method=0, double m=0.0, double s=1.0); // 挿入 void M_ins(double pr, int wd=0); // 削除 void M_del(double pr, int wd=0); // エリート・ルーレット選択 void S_roul(int elite=0, int s_method=1, double s_bias=0.0, double s_step=1.0); }; double norm_d(double, double); /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ Species::Species(char *name, long seed) { int i1, kind, num; FILE *in; /* データの入力 */ in = fopen(name, "r"); fscanf(in,"%*s %d %*s %d", &allele_u, &allele_l); fscanf(in,"%*s %d %*s %d", &max_len, &min_len); fscanf(in,"%*s %d %*s %d", &dup_a, &dup_s); fscanf(in,"%*s %d %*s %d", &size, &max_ch); /* データのチェック */ if (size <= 0) { printf("***error 個体総数≦0 (Constructor)\n"); exit(1); } if (max_ch < 0) { printf("***error 子供の数<0 (Constructor)\n"); exit(1); } if (max_len <= 0 || min_len == 0) { printf("***error 遺伝子長≦0 (Constructor)\n"); exit(1); } if (max_len < min_len) { printf("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n"); exit(1); } if (allele_u <= allele_l) { printf("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n"); exit(1); } kind = allele_u - allele_l + 1; if (dup_a == 0 && max_len > kind) { printf("***error 遺伝子の重複を防ぐことはできない (Constructor)\n"); exit(1); } /* 領域の確保 */ num = size + max_ch; ind = new int * [num]; for (i1 = 0; i1 < num; i1++) ind[i1] = new int [max_len]; edge = new int * [max_len]; for (i1 = 0; i1 < max_len; i1++) edge[i1] = new int [5]; pi = new double [num]; ro = new double [num]; len = new int [num]; kou1 = new int [max_len]; kou2 = new int [max_len]; s_w = new int [num]; pi_w = new char [num]; /* 乱数の初期設定 */ init_genrand(seed); } /****************/ /* デストラクタ */ /****************/ Species::~Species() { int i1; for (i1 = 0; i1 < size+max_ch; i1++) delete [] ind[i1]; delete [] ind; for (i1 = 0; i1 < max_len; i1++) delete [] edge[i1]; delete [] edge; delete [] pi; delete [] len; delete [] kou1; delete [] kou2; delete [] pi_w; delete [] s_w; delete [] ro; } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ int Species::Position(int n) { int i1, k = -1, sw = 0; /* 空いている場所を探す */ if (n < 0) { 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); } } /* n番目の親(pi_w[i]=2)を捜す */ else { for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] == 2) { k++; if (k == n) { sw = 1; k = i1; } } } } return k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値(default=0) */ /* step : β(default=1) */ /* return : 個体番号 */ /*******************************************************************/ int Species::Select(int method, double bias, double step) { double sum = 0.0, x; int i1, k, min, n, sw; // ルーレット板の用意 switch (method) { // ランダム case -1: n = 0; 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; } break; // 評価値をそのまま利用 case 0: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += pi[i1]; n++; } } if (fabs(sum) > 1.0e-10) { sum = 1.0 / fabs(sum); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = pi[i1] * sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 最小値からの差 case 1: min = -1; n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { n++; if (min < 0 || pi[i1] < pi[min]) min = i1; } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = pi[i1] - pi[min]; if (ro[i1] < bias) ro[i1] = bias; sum += ro[i1]; } } if (sum > 1.0e-10) { sum = 1.0 / sum; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 線形化 case 2: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = -1.0; n++; } else ro[i1] = 1.0; } sw = 0; sum = bias; while (sw == 0) { min = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (ro[i1] < 0.0 && (min < 0 || pi[i1] < pi[min])) min = i1; } if (min < 0) sw = 1; else { ro[min] = sum; sum += step; } } sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } break; } 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; } /********************/ /* 標準的な初期設定 */ /********************/ void Species::Init_std() { int i1, i2, i3, length, lid, 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) { // 遺伝子長の決定 if (min_len < 0) length = max_len; else { length = (int)(genrand_real3() * (max_len - min_len + 1) + min_len); if (length > max_len) length = max_len; } len[i1] = length; // 遺伝子の決定 for (i2 = 0; i2 < length; i2++) { sw2 = 0; while (sw2 == 0) { lid = (int)(genrand_real3() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; ind[i1][i2] = lid; // 重複遺伝子のチェック sw2 = 1; if (dup_a == 0) { for (i3 = 0; i3 < i2 && sw2 > 0; i3++) { if (lid == ind[i1][i3]) sw2 = 0; } } } } // 重複個体のチェック sw1 = 1; if (dup_s == 0) { for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { if (len[i1] == len[i2]) { sw2 = 0; for (i3 = 0; i3 < len[i1] && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ void Species::Out_std(int sw, int out_m, int gen, char *name) { int i1, i2, k = 0, pr; char *now; time_t aclock; FILE *out; if (sw >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); scanf("%d", &pr); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) { out = stdout; getchar(); } else { time(&aclock); now = ctime(&aclock); out = fopen(name, "a"); fprintf(out, "***世代 %d 適応度 max %f (%d) mean %f 時間 %s\n", gen, max, max_n, mean, now); } // 詳細出力 for (i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { fprintf(out, "%d allele", i1); for (i2 = 0; i2 < len[i1]; i2++) fprintf(out, " %d", ind[i1][i2]); fprintf(out, " value %f\n", pi[i1]); if (pr > 0) { k++; if (k == pr) { getchar(); k = 0; } } } } if (pr < 0) fclose(out); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供)(default) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数(default=max_ch/2) */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_copy(int method, int pair, int k_method, double k_bias, double k_step) { int i1, i2, i3, k, p, p1, p2, sw; /* 初期設定とデータチェック */ if (method != 1) method = 2; if (pair <= 0) pair = (method==2) ? max_ch/2 : max_ch; else { if (method == 2 && 2*pair > max_ch || method == 1 && pair > max_ch) { printf("***error 子供が多すぎる (C_copy)\n"); exit(1); } } /* 実行 */ for (i1 = 0; i1 < pair; i1++) { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // コピー for (i2 = 0; i2 < method; i2++) { p = (i2 == 0) ? p1 : p2; k = Position(-1); len[k] = len[p]; pi_w[k] = 1; for (i3 = 0; i3 < len[k]; i3++) ind[k][i3] = ind[p][i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数(default=1) */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉(default) */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_point(double kosa, int k_point, int k_vr, int k_method, double k_bias, double k_step) { int abs_p, c1, c2, i1, i2, i3, k1, k2, mn = 0, num, p1, p2, pair, sw, t11, t12, t21, t22; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { printf("***error 交叉方法が不適当 (C_point)\n"); exit(1); } abs_p = abs(k_point); if (abs_p == 0 || abs_p > max_len-1 || min_len > 0 && abs_p > min_len-1) { printf("***error 交叉点の数が不適当 (C_point)\n"); exit(1); } if (k_vr > 0 && min_len < 0) { printf("***error 遺伝子長は可変でなければならない (C_point)\n"); exit(1); } /* 交叉 */ num = k_point; for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 交叉位置の数の決定 if (k_point < 0) { num = (int)(genrand_real3() * abs_p + 1); if (num > abs_p) num = abs_p; } // 交叉位置の決定(点の後ろで交叉) for (i2 = 0; i2 < num; i2++) { // 親1の交叉位置 sw = 0; while (sw == 0) { sw = 1; kou1[i2] = (int)(genrand_real3() * (len[p1] - 1)); if (kou1[i2] > len[p1]-2) kou1[i2] = len[p1] - 2; if (k_vr == 0 && kou1[i2] > len[p2]-2) kou1[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou1[i3] == kou1[i2]) sw = 0; } } // 親2の交叉位置 if (k_vr > 0) { sw = 0; while (sw == 0) { sw = 1; kou2[i2] = (int)(genrand_real3() * (len[p2] - 1)); if (kou2[i2] > len[p2]-2) kou2[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou2[i3] == kou2[i2]) sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ c1 = 0; c2 = 0; t11 = 0; t21 = 0; // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; for (i2 = 0; i2 < num+1; i2++ ) { // 次の交叉位置を求める if (i2 == num) { // 最後 t12 = len[p1]; t22 = len[p2]; } else { // 親1 t12 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou1[i3] >= 0 && kou1[i3] <= t12) { t12 = kou1[i3]; mn = i3; } } kou1[mn] = -1; t12++; // 親2 if (k_vr == 0) t22 = t12; else { t22 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou2[i3] >= 0 && kou2[i3] <= t22) { t22 = kou2[i3]; mn = i3; } } kou2[mn] = -1; t22++; } } // 指定箇所のコピー for (i3 = t11; i3 < t12; i3++) { if (i2%2 == 0) { if (c1 < max_len) { ind[k1][c1] = ind[p1][i3]; c1++; } } else { if (c2 < max_len) { ind[k2][c2] = ind[p1][i3]; c2++; } } } for (i3 = t21; i3 < t22; i3++) { if (i2%2 == 0) { if (c2 < max_len) { ind[k2][c2] = ind[p2][i3]; c2++; } } else { if (c1 < max_len) { ind[k1][c1] = ind[p2][i3]; c1++; } } } // 交叉位置の移動 t11 = t12; t21 = t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_uniform(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k1, k2, p1, p2, pair, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { printf("***error 交叉方法が不適当 (C_uniform)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_uniform)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; 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]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_mean(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k, p1, p2, sw; /* 初期設定とデータのチェック */ if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_mean)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < max_ch; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(1, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); len[k] = len[p1]; pi_w[k] = 1; // 交叉 for (i2 = 0; i2 < len[k]; i2++) ind[k][i2] = (ind[p1][i2] + ind[p2][i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_cycle(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_cycle)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_cycle)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 初期設定 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = 0; kou2[i2] = 0; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 sw = 0; while (sw == 0) { sw = 1; p = (int)(genrand_real3() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; if (kou1[p] == 0 && kou2[p] == 0) { kou1[p] = 1; kou2[p] = 1; ind[k1][p] = ind[p1][p]; ind[k2][p] = ind[p2][p]; for (i2 = 0; i2 < len[p1] && sw > 0; i2++) { if (ind[p2][p] == ind[p1][i2]) { ind[k1][i2] = ind[p1][i2]; kou1[i2] = 1; sw = 0; } } sw = 1; for (i2 = 0; i2 < len[p2] && sw > 0; i2++) { if (ind[p1][p] == ind[p2][i2]) { ind[k2][i2] = ind[p2][i2]; kou2[i2] = 1; sw = 0; } } } } sw = 0; i2 = 0; i3 = 0; while (sw == 0) { while (sw == 0 && i2 < len[p1]) { if (kou1[i2] == 0) sw = 1; else i2++; } sw = 0; while (sw == 0 && i3 < len[p2]) { if (kou2[i3] == 0) sw = 1; else i3++; } if (i2 < len[p1] && i3 < len[p2]) { ind[k1][i2] = ind[p2][i3]; ind[k2][i3] = ind[p1][i2]; sw = 0; i2++; i3++; } else sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_part(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, lv, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_part)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_part)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(genrand_real3() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } for (i2 = p; i2 < len[p1]; i2++) { sw = 0; lv = ind[k1][i2]; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (ind[k2][i2] == ind[k1][i3]) { ind[k1][i2] = ind[k1][i3]; ind[k1][i3] = lv; sw = 1; } } sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (lv == ind[k2][i3]) { ind[k2][i3] = ind[k2][i2]; ind[k2][i2] = lv; sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_seq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, pp, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_seq)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_seq)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(genrand_real3() * (len[p1] - 1)); if (p >= len[p1]-1) p = len[p1] - 2; for (i2 = 0; i2 <= p; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } pp = 0; for (i2 = p+1; i2 < len[p1]; i2++) { sw = 0; for (i3 = pp; i3 < len[p2] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4]) { sw = 1; pp = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } pp = 0; for (i2 = p+1; i2 < len[p2]; i2++) { sw = 0; for (i3 = pp; i3 < len[p1] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4]) { sw = 1; pp = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_useq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_useq)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_useq)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; kou1[i2] = (genrand_real3() < 0.5) ? 0 : 1; } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p2] && sw == 0; i3++) { for (i4 = 0; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p1] && sw == 0; i3++) { for (i4 = 0; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_upos(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_upos)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_upos)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = (genrand_real3() < 0.5) ? 0 : 1; if (kou1[i2] > 0) { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p1][i2] == ind[k1][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k1][i3] = ind[p1][i2]; p = i3 + 1; sw = 1; } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { sw = 0; for (i3 = 0; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p2][i2] == ind[k2][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k2][i3] = ind[p2][i2]; p = i3 + 1; sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ void Species::C_edge(double kosa, int k_method, double k_bias, double k_step) { int e[2], i1, i2, i3, i4, i5, k, kk, k0 = 0, k1, k2, min, num, p, pair, p1, p2, sw; /* 初期設定とデータのチェック */ pair = max_ch; if (dup_a != 0) { printf("***error 交叉方法が不適当 (C_edge)\n"); exit(1); } if (min_len > 0) { printf("***error 遺伝子長は固定長でなければならない (C_edge)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(1, 1); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); pi_w[k] = 1; len[k] = len[p1]; // エッジマップの初期化 for (i2 = 0; i2 < len[k]; i2++) { edge[i2][0] = 0; for (i3 = 1; i3 <= 4; i3++) edge[i2][i3] = -1; } // 交叉 // エッジマップの作成 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p1][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p1][len[k]-1]; e[1] = ind[p1][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p1][i3-1]; e[1] = ind[p1][0]; } else { e[0] = ind[p1][i3-1]; e[1] = ind[p1][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p2][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p2][len[k]-1]; e[1] = ind[p2][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p2][i3-1]; e[1] = ind[p2][0]; } else { e[0] = ind[p2][i3-1]; e[1] = ind[p2][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { sw = 1; for (i5 = 1; i5 <= edge[i2][0] && sw == 1; i5++) { if (edge[i2][i5] == e[i4]) sw = 2; } if (sw == 1) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } } } // 交叉の実行 // 出発点の決定 k1 = ind[p1][0]; k2 = ind[p2][0]; if (edge[k1][0] == edge[k2][0]) kk = (genrand_real3() > 0.5) ? k2 : k1; else kk = (edge[k1][0] < edge[k2][0]) ? k1 : k2; ind[k][0] = kk; p = 1; while (p < len[k]) { // ノードの除去 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; if (edge[i2][0] > 0) { for (i3 = 1; i3 <= 4 && sw == 0; i3++) { if (edge[i2][i3] == kk) { sw = 1; edge[i2][i3] = -1; edge[i2][0]--; } } } } // 次の現在ノードの選択 min = 10; num = 0; for (i2 = 1; i2 <= 4; i2++) { if (edge[kk][i2] >= 0) { k1 = edge[kk][i2]; if (edge[k1][0] >= 0 && edge[k1][0] < min) { num = 1; min = edge[k1][0]; k0 = k1; } else { if (edge[k1][0] == min) num++; } } } if (num > 1) { k1 = (int)(genrand_real3() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 1; i2 <= 4 && k0 < 0; i2++) { if (edge[kk][i2] >= 0) { if (edge[edge[kk][i2]][0] == min) { k2++; if (k1 == k2) k0 = edge[kk][i2]; } } } } else { if (num <= 0) { num = 0; for (i2 = 0; i2 < len[k]; i2++) { if (i2 != kk && edge[i2][0] >= 0) num++; } if (num <= 0) { printf("***error invalid data (C_edge)\n"); exit(1); } else { k1 = (int)(genrand_real3() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 0; i2 < len[k] && k0 < 0; i2++) { if (i2 != kk && edge[i2][0] >= 0) { k2++; if (k1 == k2) k0 = i2; } } } } } edge[kk][0] = -1; ind[k][p] = k0; kk = k0; p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数(default=10) */ /*************************************************************/ void Species::C_sub(double kosa, int count) { int i1, i2, i3, i4, i5, k1, k2, k3, k4, p1, p2, t11, t12, t21, t22 = 0, sw; /* 初期設定とデータのチェック */ if ((4*count*size*(size-1)) > max_ch) { printf("***error 子供が多すぎる (C_sub)\n"); exit(1); } /* 交叉 */ for (i1 = 0; i1 < size-1; i1++) { // 親1 p1 = Position(i1); if (p1 >= 0) { for (i2 = i1; i2 < size; i2++) { // 親2 p2 = Position(i2); if (p2 >= 0) { // 交叉しない場合 if (genrand_real3() > kosa) C_copy(2, 1); // 交叉する場合 else { // 交叉回数の制御 for (i3 = 0; i3 < count; i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 t11 = (int)(genrand_real3() * len[p1]); if (t11 > (len[p1]-1)) t11 = len[p1] - 1; sw = 0; while (sw == 0) { t12 = (int)(genrand_real3() * len[p1]); if (t12 > (len[p1]-1)) t12 = len[p1] - 1; if (t12 != t11) sw = 1; } if (t11 > t12) { k1 = t11; t11 = t12; t12 = k1; } // 親2の交叉位置 sw = 0; t21 = -1; for (i4 = 0; i4 < len[p2] && t21 < 0; i4++) { for (i5 = t11; i5 <= t12 && t21 < 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) t21 = i4; } } if (t21 >= 0) { t22 = t21 + t12 - t11; if (t22 < len[p2]) { sw = 1; for (i4 = t21+1; i4 <= t22 && sw > 0; i4++) { sw = 0; for (i5 = t11; i5 <= t12 && sw == 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) sw = 1; } } } } // 交叉の実行 if (sw > 0) { k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p1]; k3 = Position(-1); pi_w[k3] = 1; len[k3] = len[p2]; k4 = Position(-1); pi_w[k4] = 1; len[k4] = len[p2]; for (i4 = 0; i4 < t11; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = t11; i4 <= t12; i4++) { ind[k1][i4] = ind[p2][t21+i4-t11]; ind[k2][i4] = ind[p2][t22-i4+t11]; } for (i4 = t12+1; i4 < len[p1]; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = 0; i4 < t21; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } for (i4 = t21; i4 <= t22; i4++) { ind[k3][i4] = ind[p1][t11+i4-t21]; ind[k4][i4] = ind[p1][t12-i4+t21]; } for (i4 = t22+1; i4 < len[p2]; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ void Species::M_alle(double pr) { int i1, i2, lid; /* データのチェックと初期設定 */ if (dup_a == 0) { printf("***error 突然変異方法が不適当 (M_alle)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (genrand_real3() <= pr) { lid = (int)(genrand_real3() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; if (lid != ind[i1][i2]) ind[i1][i2] = lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ void Species::M_move(double pr) { int i1, i2, ld, p1, p2, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 位置の決定 */ // p1 p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p2 sw = 0; while (sw == 0) { p2 = (int)(genrand_real3() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } /* 実行 */ if (p2 > p1) { ld = ind[i1][p2]; for (i2 = p2; i2 > p1; i2--) ind[i1][i2] = ind[i1][i2-1]; ind[i1][p1] = ld; } else { ld = ind[i1][p2]; for (i2 = p2; i2 < p1-1; i2++) ind[i1][i2] = ind[i1][i2+1]; ind[i1][p1-1] = ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /********************************************************/ void Species::M_inv(double pr, int wd) { int i1, lid, p, p1, p2, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(genrand_real3() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(genrand_real3() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ sw = 0; while (sw == 0) { lid = ind[i1][p1]; ind[i1][p1] = ind[i1][p2]; ind[i1][p2] = lid; p1++; p2--; if (p1 >= p2) sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_scram(double pr, int wd) { int i1, i2, ld, p, p1, p2, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(genrand_real3() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(genrand_real3() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ for (i2 = p1; i2 <= p2; i2++) { p = (int)(genrand_real3() * (p2 - p1 + 1) + p1); if (p > p2) p = p2; ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_chg(double pr, int wd) { int i1, i2, ld, p, p1, p2, p3, p4, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { /* 区間等の決定([p1,p2]と[p3,p4]の入れ替え) */ // p1 p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(genrand_real3() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 小さい方をp1,p2にする if (p1 > p3) { p = p1; p1 = p3; p3 = p; } // p4, p2 p4 = (wd == 0) ? (int)(genrand_real3() * (len[i1] - p3)) + p3 : p1 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); // 重複部分のチェック if (p2 >= p3) { p = p3 - 1; p3 = p2 + 1; p2 = p; p4 = p3 + (p2 - p1); } /* 実行 */ p = p3; for (i2 = p1; i2 <= p2; i2++) { ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(deafult) */ /**********************************************************************/ void Species::M_dup(double pr, int wd) { int i1, i2, p, p1, p2, p3, p4, sw; /* データのチェック */ if (dup_a == 0) { printf("***error 突然変異方法が不適当 (M_dup)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 p1 = (int)(genrand_real3() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(genrand_real3() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 区間を決める if (p3 > p1) { p4 = (wd == 0) ? (int)(genrand_real3() * (len[i1] - p3)) + p3 : p3 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); } else { p2 = (wd == 0) ? (int)(genrand_real3() * (len[i1] - p1)) + p1 : p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; p4 = p3 + (p2 - p1); } // 実行 p = p4; for (i2 = p2; i2 >= p1; i2--) { ind[i1][p] = ind[i1][i2]; p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布(default) */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限(default=0.0) */ /* s : 標準偏差または一様分布の上限(default=1.0) */ /******************************************************/ void Species::M_per(double pr, int method, double m, double s) { double w, wd = 0.0, x1; int i1, i2; /* データのチェックと初期設定 */ if (dup_a == 0) { printf("***error 突然変異方法が不適当 (M_per)\n"); exit(1); } if (method > 0) wd = s - m; /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (genrand_real3() <= pr) { if (method == 0) w = norm_d(m, s); else { w = genrand_real3() * wd; if (genrand_real3() < 0.5) w = -w; } x1 = (double)ind[i1][i2] + w; if (x1 > allele_u) x1 = allele_u; else { if (x1 < allele_l) x1 = allele_l; } ind[i1][i2] = (int)x1; } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_ins(double pr, int wd) { int i1, i2, l, ld, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { printf("***error 突然変異方法が不適当 (M_ins)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { // 挿入位置の決定 p = (int)(genrand_real3() * (len[i1]+1)); if (p > len[i1]) p = len[i1]; // 挿入する遺伝子長の決定 l = (wd == 0) ? (int)(genrand_real3() * (max_len - len[i1] + 1)) : wd; if (l > max_len-len[i1]) l = max_len - len[i1]; else { if (l <= 0) l = 1; } // 実行 // 挿入場所の確保 if (p < len[i1]) { for (i2 = len[i1]+l-1; i2 >= p; i2--) ind[i1][i2] = ind[i1][i2-l]; } // 挿入場所の遺伝子の決定 for (i2 = p; i2 < p+l; i2++) { ld = (int)(genrand_real3() * (allele_u - allele_l + 1) + allele_l); if (ld > allele_u) ld = allele_u; ind[i1][i2] = ld; } len[i1] += l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ void Species::M_del(double pr, int wd) { int i1, i2, l, max, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { printf("***error 突然変異方法が不適当 (M_del)\n"); exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && genrand_real3() <= pr) { // 削除位置の決定 p = (int)(genrand_real3() * len[i1]); if (p >= len[i1]) p = len[i1] - 1; // 削除する遺伝子長の決定 max = (len[i1]-min_len < len[i1]-p) ? len[i1] - min_len : len[i1] - p; l = (wd == 0) ? (int)(genrand_real3() * max + 1) : wd; if (l > max) l = max; // 実行 for (i2 = 0; i2 < len[i1]-p-l; i2++) ind[i1][p+i2] = ind[i1][p+i2+l]; len[i1] -= l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ void Species::S_roul(int elite, int s_method, double s_bias, double s_step) { int count = 0, i1, i2, i3, k = 0, max, n = 0, p, sw; /* 値のチェックと初期設定 */ if (s_method != 0 && s_method != 2) s_method = 1; if (elite > size) { printf("***error エリートで残す数が多すぎる (S_roul)\n"); exit(1); } if (s_method == 2 && s_step <= 0.0) s_step = 1.0; for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; /* 重複個体を削除 */ if (dup_s == 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 && len[i1] == len[i2]) { sw = 0; for (i3 = 0; i3 < len[i1] && 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 || dup_s == 0 && n < size) { 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++; } } // ルーレット選択 while (count < size+max_ch && k < size) { p = Select(s_method, s_bias, s_step); if (dup_s == 0 && s_w[p] > 0) count++; else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (dup_s == 0 && k < size) { for (i1 = 0; i1 < size+max_ch && k < size; 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(-1); len[k] = len[i1]; pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < len[i1]; i3++) ind[k][i3] = ind[i1][i3]; } } } } } /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ double norm_d(double m, double s) { double x = 0.0; int i1; for (i1 = 0; i1 < 12; i1++) x += genrand_real3(); x = s * (x - 6.0) + m; return x; } /************************/ /* クラスFunctionの定義 */ /************************/ class Function : public Species { double cv; // 2進数を10進数の変換する係数 int max_gen; // 最大世代交代数 int kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 多点交叉 // =2 : 一様交叉 // =3 : 平均化交叉 double kosa; // 交叉確率 int k_point; // 交差点の数(負の時は,1から-point間のランダム) int k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) int k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double k_bias; // α,または,method=2の場合は初期値 double k_step; // β int mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 対立遺伝子への置換 // =1 : 移動 // =2 : 逆位 // =3 : スクランブル // =4 : 転座 // =5 : 重複 // =6 : 摂動 double mute; // 突然変異率 int wd; // 突然変異に使用する部分遺伝子長 double m_mean; // 摂動の平均値 double m_std; // 摂動の標準偏差 int elite; // エリート選択で残す数 int s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double s_bias; // α,または,s_method=2の場合は初期値 double s_step; // β int out_d; // 表示間隔 int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) int out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 char o_file[100]; // 出力ファイル名 public: // コンストラクタ Function (char *, char *, long); // デストラクタ ~Function (); // 全体の実行制御 void Control(); // 適応度の計算 void Adap(); // 出力 void Output(int); }; /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : Function定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ Function::Function (char *name1, char *name2, long seed) : Species (name1, seed) { FILE *in; in = fopen(name2, "r"); fscanf(in, "%*s %d %*s %d", &out_lvl, &out_m); fscanf(in, "%*s %s %*s %d", o_file, &out_d); fscanf(in, "%*s %d %*s %lf %*s %d %*s %d %*s %d %*s %lf %*s %lf", &kosa_m, &kosa, &k_point, &k_vr, &k_method, &k_bias, &k_step); fscanf(in, "%*s %d %*s %lf %*s %d %*s %lf %*s %lf", &mute_m, &mute, &wd, &m_mean, &m_std); fscanf(in, "%*s %d %*s %d %*s %lf %*s %lf", &elite, &s_method, &s_bias, &s_step); fscanf(in, "%*s %d", &max_gen); cv = 1.0 / (pow(2.0, (double)max_len) - 1.0); fclose(in); } /****************/ /* デストラクタ */ /****************/ Function::~Function() { int i1; for (i1 = 0; i1 < size+max_ch; i1++) delete [] ind[i1]; delete [] ind; for (i1 = 0; i1 < max_len; i1++) delete [] edge[i1]; delete [] edge; delete [] pi; delete [] len; delete [] kou1; delete [] kou2; delete [] pi_w; delete [] s_w; delete [] ro; } /**************/ /* 全体の制御 */ /**************/ void Function::Control() { int gen = 1, k1; // 初期集団の発生 Init_std(); // 評価 Adap(); // 出力 printf("***世代 %d 適応度 max %f (%d) mean %f\n", gen, max, max_n, mean); if (abs(out_lvl) > 0) Output(gen); // 世代交代 for (gen = 2; gen <= max_gen; gen++) { // 交叉 switch (kosa_m) { case -1: break; case 0: C_copy(); // 親のコピー break; case 1: C_point(kosa, k_point); // 多点交叉 break; case 2: C_uniform(kosa); // 一様交叉 break; case 3: C_mean(kosa); // 平均化交叉 break; default: break; } // 突然変異 switch (mute_m) { case -1: break; case 0: M_alle(mute); // 対立遺伝子への置換 break; case 1: M_move(mute); // 移動 break; case 2: M_inv(mute, wd); // 逆位 break; case 3: M_scram(mute, wd); // スクランブル break; case 4: M_chg(mute, wd); // 転座 break; case 5: M_dup(mute, wd); // 重複 break; case 6: M_per(mute, wd, m_mean, m_std); // 摂動 break; default: break; } // 適応度 Adap(); // 淘汰 S_roul(elite); // 出力 if (gen%out_d == 0) printf("***世代 %d 適応度 max %f (%d) mean %f\n", gen, max, max_n, mean); if (abs(out_lvl) > 0) { if (gen%abs(out_lvl) == 0) Output(gen); } } gen--; k1 = out_m; out_m = 0; printf("***世代 %d 適応度 max %f (%d) mean %f\n", gen, max, max_n, mean); Output(gen); out_m = k1; } /****************/ /* 適応度の計算 */ /****************/ void Function::Adap() { double x, y; int i1, i2, n = 0; max = 0.0; max_n = -1; mean = 0.0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { x = 0.0; y = 0.0; for (i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += pow(2.0, y); y += 1.0; } x *= cv; pi[i1] = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x+50.0); pi_w[i1] = 2; } if (pi_w[i1] > 0) { mean += pi[i1]; n++; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } mean /= n; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ void Function::Output(int gen) { double x, y; int i1, i2, k = 0, pr; char *now; time_t aclock; FILE *out; if (out_lvl >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); scanf("%d", &pr); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) { out = stdout; getchar(); } else { time(&aclock); now = ctime(&aclock); out = fopen(o_file, "a"); fprintf(out, "***世代 %d 適応度 max %f (%d) mean %f 時間 %s\n", gen, max, max_n, mean, now); } // 詳細出力 for (i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { fprintf(out, "%d allele", i1); for (i2 = 0; i2 < len[i1]; i2++) fprintf(out, " %d", ind[i1][i2]); x = 0.0; y = 0.0; for (i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += pow(2.0, y); y += 1.0; } x *= cv; fprintf(out, " x %f y %f\n", x, pi[i1]); if (pr > 0) { k++; if (k == pr) { getchar(); k = 0; } } } } if (pr < 0) fclose(out); } } /****************/ /* main program */ /****************/ int main(int argc, char *argv[]) { long *seed; int i1, n; char **i_file1, **i_file2; FILE *in; Function *fn; // 入力ミス if (argc <= 1) { printf("***error ファイル名を入力して下さい\n"); exit(1); } // 入力OK else { // ファイルのオープン in = fopen(argv[1], "r"); if (in == NULL) { printf("***error ファイル名が不適当です\n"); exit(1); } // 入力データファイル名の入力 fscanf(in, "%d", &n); // データの数 seed = new long [n]; i_file1 = new char * [n]; i_file2 = new char * [n]; for (i1 = 0; i1 < n; i1++) { i_file1[i1] = new char [100]; i_file2[i1] = new char [100]; seed[i1] = 1000 * i1 + 1234567; fscanf(in, "%s %s", i_file1[i1], i_file2[i1]); } fclose(in); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { printf("\n+++++ケース %d+++++\n", i1+1); fn = new Function (i_file1[i1], i_file2[i1], seed[i1]); fn->Control(); } } return 0; } //------------------ケーススタディデータ(data_cf.txt)------ /* 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt */ //------------------Species記述データ(data1_f.txt)--------- /* 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 */ //------------------Function記述データ(data2_f.txt)-------- /* 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 */ //---------------------MT.h--------------------------- // A C-program for MT19937, with initialization improved 2002/1/26. // Coded by Takuji Nishimura and Makoto Matsumoto. // // Before using, initialize the state by using init_genrand(seed) // or init_by_array(init_key, key_length). // // Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The names of its contributors may not be used to endorse or promote // products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // // Any feedback is very welcome. // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html // email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) // The original version of http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c was modified by Takahiro Omi as // - delete line 47 "#include<stdio.h>" // - delete line 174 int main(void){...} // - change N -> MT_N // - change N -> MT_N // - change the file name "mt19937ar.c" -> "MT.h" /* // Period parameters #define MT_N 624 #define MT_M 397 #define MATRIX_A 0x9908b0dfUL // constant vector a #define UPPER_MASK 0x80000000UL // most significant w-r bits #define LOWER_MASK 0x7fffffffUL // least significant r bits static unsigned long mt[MT_N]; // the array for the state vector static int mti=MT_N+1; // mti==MT_N+1 means mt[MT_N] is not initialized // initializes mt[MT_N] with a seed void init_genrand(unsigned long s) { mt[0]= s & 0xffffffffUL; for (mti=1; mti<MT_N; mti++) { mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. // In the previous versions, MSBs of the seed affect // only MSBs of the array mt[]. // 2002/01/09 modified by Makoto Matsumoto mt[mti] &= 0xffffffffUL; // for >32 bit machines } } // initialize by an array with array-length // init_key is the array for initializing keys // key_length is its length // slight change for C++, 2004/2/26 void init_by_array(unsigned long init_key[], int key_length) { int i, j, k; init_genrand(19650218UL); i=1; j=0; k = (MT_N>key_length ? MT_N : key_length); for (; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; j++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } if (j>=key_length) j=0; } for (k=MT_N-1; k; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i; // non linear mt[i] &= 0xffffffffUL; // for WORDSIZE > 32 machines i++; if (i>=MT_N) { mt[0] = mt[MT_N-1]; i=1; } } mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array } // generates a random number on [0,0xffffffff]-interval unsigned long genrand_int32(void) { unsigned long y; static unsigned long mag01[2]={0x0UL, MATRIX_A}; // mag01[x] = x * MATRIX_A for x=0,1 if (mti >= MT_N) { // generate N words at one time int kk; if (mti == MT_N+1) // if init_genrand() has not been called, init_genrand(5489UL); // a default initial seed is used for (kk=0;kk<MT_N-MT_M;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+MT_M] ^ (y >> 1) ^ mag01[y & 0x1UL]; } for (;kk<MT_N-1;kk++) { y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); mt[kk] = mt[kk+(MT_M-MT_N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; } y = (mt[MT_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MT_N-1] = mt[MT_M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mti = 0; } y = mt[mti++]; // Tempering y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } // generates a random number on [0,0x7fffffff]-interval long genrand_int31(void) { return (long)(genrand_int32()>>1); } // generates a random number on [0,1]-real-interval double genrand_real1(void) { return genrand_int32()*(1.0/4294967295.0); // divided by 2^32-1 } // generates a random number on [0,1)-real-interval double genrand_real2(void) { return genrand_int32()*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on (0,1)-real-interval double genrand_real3(void) { return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); // divided by 2^32 } // generates a random number on [0,1) with 53-bit resolution double genrand_res53(void) { unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; return(a*67108864.0+b)*(1.0/9007199254740992.0); } // These real versions are due to Isaku Wada, 2002/01/09 added */
/***********************************/ /* 遺伝的アルゴリズムによるTSPの解 */ /* coded by Y.Suganuma */ /***********************************/ import java.io.*; import java.util.Random; import java.util.Date; import java.util.StringTokenizer; import java.awt.*; import java.awt.event.*; /***********************/ /* クラスSpeciesの定義 */ /***********************/ class Species { protected double max; // 最大適応度 protected double mean; // 平均適応度 protected double [] pi; // 適応度 protected double [] ro; // ルーレット板 protected int allele_u; // 対立遺伝子上限 protected int allele_l; // 対立遺伝子下限 protected int size; // 個体総数 protected int max_ch; // 子供の数の最大値 protected int max_len; // 最大遺伝子長 protected int min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) protected int max_n; // 最大適応度の個体番号 protected int dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す protected int dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す protected int [][] ind; // 集団(個体の集まり) protected int [] len; // 各個体の遺伝子長 protected int [] kou1; // 交叉・突然変異用作業場所1 protected int [] kou2; // 交叉・突然変異用作業場所2 protected int [] s_w; // 淘汰用指標(選択された回数) protected int [][] edge; // エッジ組み替え交叉用ワークエリア protected byte [] pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) protected Random rn; // 乱数 /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ double norm_d(double m, double s) { double x = 0.0; int i1; for (i1 = 0; i1 < 12; i1++) x += rn.nextDouble(); x = s * (x - 6.0) + m; return x; } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ int Position(int n) { int i1, k = -1, sw = 0; /* 空いている場所を探す */ if (n < 0) { for (i1 = 0; i1 < size+max_ch && k < 0; i1++) { if (pi_w[i1] == 0) k = i1; } if (k < 0) { System.out.print("***error 空いている場所がない --Position--\n"); System.exit(1); } } /* n番目の親(pi_w[i]=2)を捜す */ else { for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] == 2) { k++; if (k == n) { sw = 1; k = i1; } } } } return k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値 */ /* step : β */ /* return : 個体番号 */ /*******************************************************************/ int Select(int method, double bias, double step) { double sum = 0.0, x; int i1, k, min, n, sw; // ルーレット板の用意 switch (method) { // ランダム case -1: n = 0; 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; } break; // 評価値をそのまま利用 case 0: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += pi[i1]; n++; } } if (Math.abs(sum) > 1.0e-10) { sum = 1.0 / Math.abs(sum); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = pi[i1] * sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 最小値からの差 case 1: min = -1; n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { n++; if (min < 0 || pi[i1] < pi[min]) min = i1; } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = pi[i1] - pi[min]; if (ro[i1] < bias) ro[i1] = bias; sum += ro[i1]; } } if (sum > 1.0e-10) { sum = 1.0 / sum; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 線形化 case 2: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = -1.0; n++; } else ro[i1] = 1.0; } sw = 0; sum = bias; while (sw == 0) { min = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (ro[i1] < 0.0 && (min < 0 || pi[i1] < pi[min])) min = i1; } if (min < 0) sw = 1; else { ro[min] = sum; sum += step; } } sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } break; } 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; } /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ Species (String name, int seed) throws IOException, FileNotFoundException { int kind, num; String line; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(name)); /* データの入力 */ line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); allele_u = Integer.parseInt(dt.nextToken()); dt.nextToken(); allele_l = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); max_len = Integer.parseInt(dt.nextToken()); dt.nextToken(); min_len = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); dup_a = Integer.parseInt(dt.nextToken()); dt.nextToken(); dup_s = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); size = Integer.parseInt(dt.nextToken()); dt.nextToken(); max_ch = Integer.parseInt(dt.nextToken()); /* データのチェック */ if (size <= 0) { System.out.print("***error 個体総数≦0 (Constructor)\n"); System.exit(1); } if (max_ch < 0) { System.out.print("***error 子供の数<0 (Constructor)\n"); System.exit(1); } if (max_len <= 0 || min_len == 0) { System.out.print("***error 遺伝子長≦0 (Constructor)\n"); System.exit(1); } if (max_len < min_len) { System.out.print("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n"); System.exit(1); } if (allele_u <= allele_l) { System.out.print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n"); System.exit(1); } kind = allele_u - allele_l + 1; if (dup_a == 0 && max_len > kind) { System.out.print("***error 遺伝子の重複を防ぐことはできない (Constructor)\n"); System.exit(1); } /* 領域の確保 */ num = size + max_ch; ind = new int [num][max_len]; edge = new int [max_len][5]; pi = new double [num]; ro = new double [num]; len = new int [num]; kou1 = new int [max_len]; kou2 = new int [max_len]; s_w = new int [num]; pi_w = new byte [num]; /* 乱数の初期設定 */ rn = new Random (seed); } /********************/ /* 標準的な初期設定 */ /********************/ void Init_std() { int i1, i2, i3, length, lid, 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) { // 遺伝子長の決定 if (min_len < 0) length = max_len; else { length = (int)(rn.nextDouble() * (max_len - min_len + 1) + min_len); if (length > max_len) length = max_len; } len[i1] = length; // 遺伝子の決定 for (i2 = 0; i2 < length; i2++) { sw2 = 0; while (sw2 == 0) { lid = (int)(rn.nextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; ind[i1][i2] = lid; // 重複遺伝子のチェック sw2 = 1; if (dup_a == 0) { for (i3 = 0; i3 < i2 && sw2 > 0; i3++) { if (lid == ind[i1][i3]) sw2 = 0; } } } } // 重複個体のチェック sw1 = 1; if (dup_s == 0) { for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { if (len[i1] == len[i2]) { sw2 = 0; for (i3 = 0; i3 < len[i1] && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ void Out_std(int sw, int out_m, int gen, String name) throws IOException, FileNotFoundException { int i1, i2, k = 0, pr; String now; PrintStream out = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (sw >= 0) { System.out.print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = Integer.parseInt(in.readLine()); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) out = System.out; else { Date newtime = new Date(); // 現在時刻の獲得 now = newtime.toString(); // 文字列への変換 out = new PrintStream(new FileOutputStream(name, true)); out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 詳細出力 for (i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { out.print(i1 + " allele"); for (i2 = 0; i2 < len[i1]; i2++) out.print(" " + ind[i1][i2]); out.println(" value " + pi[i1]); if (pr > 0) { k++; if (k == pr) { in.readLine(); k = 0; } } } } if (pr < 0) out.close(); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数 */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_copy(int method, int pair, int k_method, double k_bias, double k_step) { int i1, i2, i3, k, p, p1, p2 = 0, sw; /* 初期設定とデータチェック */ if (method != 1) method = 2; if (pair <= 0) pair = (method==2) ? max_ch/2 : max_ch; else { if (method == 2 && 2*pair > max_ch || method == 1 && pair > max_ch) { System.out.print("***error 子供が多すぎる (C_copy)\n"); System.exit(1); } } /* 実行 */ for (i1 = 0; i1 < pair; i1++) { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // コピー for (i2 = 0; i2 < method; i2++) { p = (i2 == 0) ? p1 : p2; k = Position(-1); len[k] = len[p]; pi_w[k] = 1; for (i3 = 0; i3 < len[k]; i3++) ind[k][i3] = ind[p][i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数 */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉 */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_point(double kosa, int k_point, int k_vr, int k_method, double k_bias, double k_step) { int abs_p, c1, c2, i1, i2, i3, k1, k2, mn = 0, num, p1, p2 = 0, pair, sw, t11, t12, t21, t22; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { System.out.print("***error 交叉方法が不適当 (C_point)\n"); System.exit(1); } abs_p = Math.abs(k_point); if (abs_p == 0 || abs_p > max_len-1 || min_len > 0 && abs_p > min_len-1) { System.out.print("***error 交叉点の数が不適当 (C_point)\n"); System.exit(1); } if (k_vr > 0 && min_len < 0) { System.out.print("***error 遺伝子長は可変でなければならない (C_point)\n"); System.exit(1); } /* 交叉 */ num = k_point; for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 交叉位置の数の決定 if (k_point < 0) { num = (int)(rn.nextDouble() * abs_p + 1); if (num > abs_p) num = abs_p; } // 交叉位置の決定(点の後ろで交叉) for (i2 = 0; i2 < num; i2++) { // 親1の交叉位置 sw = 0; while (sw == 0) { sw = 1; kou1[i2] = (int)(rn.nextDouble() * (len[p1] - 1)); if (kou1[i2] > len[p1]-2) kou1[i2] = len[p1] - 2; if (k_vr == 0 && kou1[i2] > len[p2]-2) kou1[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou1[i3] == kou1[i2]) sw = 0; } } // 親2の交叉位置 if (k_vr > 0) { sw = 0; while (sw == 0) { sw = 1; kou2[i2] = (int)(rn.nextDouble() * (len[p2] - 1)); if (kou2[i2] > len[p2]-2) kou2[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou2[i3] == kou2[i2]) sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ c1 = 0; c2 = 0; t11 = 0; t21 = 0; // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; for (i2 = 0; i2 < num+1; i2++ ) { // 次の交叉位置を求める if (i2 == num) { // 最後 t12 = len[p1]; t22 = len[p2]; } else { // 親1 t12 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou1[i3] >= 0 && kou1[i3] <= t12) { t12 = kou1[i3]; mn = i3; } } kou1[mn] = -1; t12++; // 親2 if (k_vr == 0) t22 = t12; else { t22 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou2[i3] >= 0 && kou2[i3] <= t22) { t22 = kou2[i3]; mn = i3; } } kou2[mn] = -1; t22++; } } // 指定箇所のコピー for (i3 = t11; i3 < t12; i3++) { if (i2%2 == 0) { if (c1 < max_len) { ind[k1][c1] = ind[p1][i3]; c1++; } } else { if (c2 < max_len) { ind[k2][c2] = ind[p1][i3]; c2++; } } } for (i3 = t21; i3 < t22; i3++) { if (i2%2 == 0) { if (c2 < max_len) { ind[k2][c2] = ind[p2][i3]; c2++; } } else { if (c1 < max_len) { ind[k1][c1] = ind[p2][i3]; c1++; } } } // 交叉位置の移動 t11 = t12; t21 = t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_uniform(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k1, k2, p1, p2 = 0, pair, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { System.out.print("***error 交叉方法が不適当 (C_uniform)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_uniform)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; 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]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_mean(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_mean)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < max_ch; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); len[k] = len[p1]; pi_w[k] = 1; // 交叉 for (i2 = 0; i2 < len[k]; i2++) ind[k][i2] = (ind[p1][i2] + ind[p2][i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_cycle(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_cycle)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_cycle)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 初期設定 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = 0; kou2[i2] = 0; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 sw = 0; while (sw == 0) { sw = 1; p = (int)(rn.nextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; if (kou1[p] == 0 && kou2[p] == 0) { kou1[p] = 1; kou2[p] = 1; ind[k1][p] = ind[p1][p]; ind[k2][p] = ind[p2][p]; for (i2 = 0; i2 < len[p1] && sw > 0; i2++) { if (ind[p2][p] == ind[p1][i2]) { ind[k1][i2] = ind[p1][i2]; kou1[i2] = 1; sw = 0; } } sw = 1; for (i2 = 0; i2 < len[p2] && sw > 0; i2++) { if (ind[p1][p] == ind[p2][i2]) { ind[k2][i2] = ind[p2][i2]; kou2[i2] = 1; sw = 0; } } } } sw = 0; i2 = 0; i3 = 0; while (sw == 0) { while (sw == 0 && i2 < len[p1]) { if (kou1[i2] == 0) sw = 1; else i2++; } sw = 0; while (sw == 0 && i3 < len[p2]) { if (kou2[i3] == 0) sw = 1; else i3++; } if (i2 < len[p1] && i3 < len[p2]) { ind[k1][i2] = ind[p2][i3]; ind[k2][i3] = ind[p1][i2]; sw = 0; i2++; i3++; } else sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_part(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, lv, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_part)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_part)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.nextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } for (i2 = p; i2 < len[p1]; i2++) { sw = 0; lv = ind[k1][i2]; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (ind[k2][i2] == ind[k1][i3]) { ind[k1][i2] = ind[k1][i3]; ind[k1][i3] = lv; sw = 1; } } sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (lv == ind[k2][i3]) { ind[k2][i3] = ind[k2][i2]; ind[k2][i2] = lv; sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_seq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, pp, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_seq)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_seq)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.nextDouble() * (len[p1] - 1)); if (p >= len[p1]-1) p = len[p1] - 2; for (i2 = 0; i2 <= p; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } pp = 0; for (i2 = p+1; i2 < len[p1]; i2++) { sw = 0; for (i3 = pp; i3 < len[p2] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4]) { sw = 1; pp = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } pp = 0; for (i2 = p+1; i2 < len[p2]; i2++) { sw = 0; for (i3 = pp; i3 < len[p1] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4]) { sw = 1; pp = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_useq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_useq)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_useq)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; kou1[i2] = (rn.nextDouble() < 0.5) ? 0 : 1; } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p2] && sw == 0; i3++) { for (i4 = 0; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p1] && sw == 0; i3++) { for (i4 = 0; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_upos(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_upos)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_upos)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = (rn.nextDouble() < 0.5) ? 0 : 1; if (kou1[i2] > 0) { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p1][i2] == ind[k1][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k1][i3] = ind[p1][i2]; p = i3 + 1; sw = 1; } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { sw = 0; for (i3 = 0; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p2][i2] == ind[k2][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k2][i3] = ind[p2][i2]; p = i3 + 1; sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_edge(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, i5, k, kk, k0 = 0, k1, k2, min, num, p, pair, p1, p2 = 0, sw; int e[] = new int [2]; /* 初期設定とデータのチェック */ pair = max_ch; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_edge)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_edge)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); pi_w[k] = 1; len[k] = len[p1]; // エッジマップの初期化 for (i2 = 0; i2 < len[k]; i2++) { edge[i2][0] = 0; for (i3 = 1; i3 <= 4; i3++) edge[i2][i3] = -1; } // 交叉 // エッジマップの作成 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p1][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p1][len[k]-1]; e[1] = ind[p1][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p1][i3-1]; e[1] = ind[p1][0]; } else { e[0] = ind[p1][i3-1]; e[1] = ind[p1][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p2][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p2][len[k]-1]; e[1] = ind[p2][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p2][i3-1]; e[1] = ind[p2][0]; } else { e[0] = ind[p2][i3-1]; e[1] = ind[p2][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { sw = 1; for (i5 = 1; i5 <= edge[i2][0] && sw == 1; i5++) { if (edge[i2][i5] == e[i4]) sw = 2; } if (sw == 1) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } } } // 交叉の実行 // 出発点の決定 k1 = ind[p1][0]; k2 = ind[p2][0]; if (edge[k1][0] == edge[k2][0]) kk = (rn.nextDouble() > 0.5) ? k2 : k1; else kk = (edge[k1][0] < edge[k2][0]) ? k1 : k2; ind[k][0] = kk; p = 1; while (p < len[k]) { // ノードの除去 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; if (edge[i2][0] > 0) { for (i3 = 1; i3 <= 4 && sw == 0; i3++) { if (edge[i2][i3] == kk) { sw = 1; edge[i2][i3] = -1; edge[i2][0]--; } } } } // 次の現在ノードの選択 min = 10; num = 0; for (i2 = 1; i2 <= 4; i2++) { if (edge[kk][i2] >= 0) { k1 = edge[kk][i2]; if (edge[k1][0] >= 0 && edge[k1][0] < min) { num = 1; min = edge[k1][0]; k0 = k1; } else { if (edge[k1][0] == min) num++; } } } if (num > 1) { k1 = (int)(rn.nextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 1; i2 <= 4 && k0 < 0; i2++) { if (edge[kk][i2] >= 0) { if (edge[edge[kk][i2]][0] == min) { k2++; if (k1 == k2) k0 = edge[kk][i2]; } } } } else { if (num <= 0) { num = 0; for (i2 = 0; i2 < len[k]; i2++) { if (i2 != kk && edge[i2][0] >= 0) num++; } if (num <= 0) { System.out.print("***error invalid data (C_edge)\n"); System.exit(1); } else { k1 = (int)(rn.nextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 0; i2 < len[k] && k0 < 0; i2++) { if (i2 != kk && edge[i2][0] >= 0) { k2++; if (k1 == k2) k0 = i2; } } } } } edge[kk][0] = -1; ind[k][p] = k0; kk = k0; p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数 */ /*************************************************************/ void C_sub(double kosa, int count) { int i1, i2, i3, i4, i5, k1, k2, k3, k4, p1, p2, t11, t12 = 0, t21, t22 = 0, sw; /* 初期設定とデータのチェック */ if ((4*count*size*(size-1)) > max_ch) { System.out.print("***error 子供が多すぎる (C_sub)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < size-1; i1++) { // 親1 p1 = Position(i1); if (p1 >= 0) { for (i2 = i1; i2 < size; i2++) { // 親2 p2 = Position(i2); if (p2 >= 0) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 交叉回数の制御 for (i3 = 0; i3 < count; i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 t11 = (int)(rn.nextDouble() * len[p1]); if (t11 > (len[p1]-1)) t11 = len[p1] - 1; sw = 0; while (sw == 0) { t12 = (int)(rn.nextDouble() * len[p1]); if (t12 > (len[p1]-1)) t12 = len[p1] - 1; if (t12 != t11) sw = 1; } if (t11 > t12) { k1 = t11; t11 = t12; t12 = k1; } // 親2の交叉位置 sw = 0; t21 = -1; for (i4 = 0; i4 < len[p2] && t21 < 0; i4++) { for (i5 = t11; i5 <= t12 && t21 < 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) t21 = i4; } } if (t21 >= 0) { t22 = t21 + t12 - t11; if (t22 < len[p2]) { sw = 1; for (i4 = t21+1; i4 <= t22 && sw > 0; i4++) { sw = 0; for (i5 = t11; i5 <= t12 && sw == 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) sw = 1; } } } } // 交叉の実行 if (sw > 0) { k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p1]; k3 = Position(-1); pi_w[k3] = 1; len[k3] = len[p2]; k4 = Position(-1); pi_w[k4] = 1; len[k4] = len[p2]; for (i4 = 0; i4 < t11; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = t11; i4 <= t12; i4++) { ind[k1][i4] = ind[p2][t21+i4-t11]; ind[k2][i4] = ind[p2][t22-i4+t11]; } for (i4 = t12+1; i4 < len[p1]; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = 0; i4 < t21; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } for (i4 = t21; i4 <= t22; i4++) { ind[k3][i4] = ind[p1][t11+i4-t21]; ind[k4][i4] = ind[p1][t12-i4+t21]; } for (i4 = t22+1; i4 < len[p2]; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ void M_alle(double pr) { int i1, i2, lid; /* データのチェックと初期設定 */ if (dup_a == 0) { System.out.print("***error 突然変異方法が不適当 (M_alle)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.nextDouble() <= pr) { lid = (int)(rn.nextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; if (lid != ind[i1][i2]) ind[i1][i2] = lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ void M_move(double pr) { int i1, i2, ld, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 位置の決定 */ // p1 p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p2 sw = 0; while (sw == 0) { p2 = (int)(rn.nextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } /* 実行 */ if (p2 > p1) { ld = ind[i1][p2]; for (i2 = p2; i2 > p1; i2--) ind[i1][i2] = ind[i1][i2-1]; ind[i1][p1] = ld; } else { ld = ind[i1][p2]; for (i2 = p2; i2 < p1-1; i2++) ind[i1][i2] = ind[i1][i2+1]; ind[i1][p1-1] = ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /********************************************************/ void M_inv(double pr, int wd) { int i1, lid, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.nextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.nextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ sw = 0; while (sw == 0) { lid = ind[i1][p1]; ind[i1][p1] = ind[i1][p2]; ind[i1][p2] = lid; p1++; p2--; if (p1 >= p2) sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_scram(double pr, int wd) { int i1, i2, ld, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.nextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.nextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ for (i2 = p1; i2 <= p2; i2++) { p = (int)(rn.nextDouble() * (p2 - p1 + 1) + p1); if (p > p2) p = p2; ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_chg(double pr, int wd) { int i1, i2, ld, p, p1, p2, p3 = 0, p4, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 区間等の決定([p1,p2]と[p3,p4]の入れ替え) */ // p1 p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.nextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 小さい方をp1,p2にする if (p1 > p3) { p = p1; p1 = p3; p3 = p; } // p4, p2 p4 = (wd == 0) ? (int)(rn.nextDouble() * (len[i1] - p3)) + p3 : p1 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); // 重複部分のチェック if (p2 >= p3) { p = p3 - 1; p3 = p2 + 1; p2 = p; p4 = p3 + (p2 - p1); } /* 実行 */ p = p3; for (i2 = p1; i2 <= p2; i2++) { ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_dup(double pr, int wd) { int i1, i2, p, p1, p2, p3 = 0, p4, sw; /* データのチェック */ if (dup_a == 0) { System.out.print("***error 突然変異方法が不適当 (M_dup)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.nextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 区間を決める if (p3 > p1) { p4 = (wd == 0) ? (int)(rn.nextDouble() * (len[i1] - p3)) + p3 : p3 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); } else { p2 = (wd == 0) ? (int)(rn.nextDouble() * (len[i1] - p1)) + p1 : p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; p4 = p3 + (p2 - p1); } // 実行 p = p4; for (i2 = p2; i2 >= p1; i2--) { ind[i1][p] = ind[i1][i2]; p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布 */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限 */ /* s : 標準偏差または一様分布の上限 */ /******************************************************/ void M_per(double pr, int method, double m, double s) { double w, wd = 0.0, x1; int i1, i2; /* データのチェックと初期設定 */ if (dup_a == 0) { System.out.print("***error 突然変異方法が不適当 (M_per)\n"); System.exit(1); } if (method > 0) wd = s - m; /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.nextDouble() <= pr) { if (method == 0) w = norm_d(m, s); else { w = rn.nextDouble() * wd; if (rn.nextDouble() < 0.5) w = -w; } x1 = (double)ind[i1][i2] + w; if (x1 > allele_u) x1 = allele_u; else { if (x1 < allele_l) x1 = allele_l; } ind[i1][i2] = (int)x1; } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_ins(double pr, int wd) { int i1, i2, l, ld, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { System.out.print("***error 突然変異方法が不適当 (M_ins)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { // 挿入位置の決定 p = (int)(rn.nextDouble() * (len[i1]+1)); if (p > len[i1]) p = len[i1]; // 挿入する遺伝子長の決定 l = (wd == 0) ? (int)(rn.nextDouble() * (max_len - len[i1] + 1)) : wd; if (l > max_len-len[i1]) l = max_len - len[i1]; else { if (l <= 0) l = 1; } // 実行 // 挿入場所の確保 if (p < len[i1]) { for (i2 = len[i1]+l-1; i2 >= p; i2--) ind[i1][i2] = ind[i1][i2-l]; } // 挿入場所の遺伝子の決定 for (i2 = p; i2 < p+l; i2++) { ld = (int)(rn.nextDouble() * (allele_u - allele_l + 1) + allele_l); if (ld > allele_u) ld = allele_u; ind[i1][i2] = ld; } len[i1] += l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_del(double pr, int wd) { int i1, i2, l, max, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { System.out.print("***error 突然変異方法が不適当 (M_del)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { // 削除位置の決定 p = (int)(rn.nextDouble() * len[i1]); if (p >= len[i1]) p = len[i1] - 1; // 削除する遺伝子長の決定 max = (len[i1]-min_len < len[i1]-p) ? len[i1] - min_len : len[i1] - p; l = (wd == 0) ? (int)(rn.nextDouble() * max + 1) : wd; if (l > max) l = max; // 実行 for (i2 = 0; i2 < len[i1]-p-l; i2++) ind[i1][p+i2] = ind[i1][p+i2+l]; len[i1] -= l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ void S_roul(int elite, int s_method, double s_bias, double s_step) { int count = 0, i1, i2, i3, k = 0, max, n = 0, p, sw; /* 値のチェックと初期設定 */ if (s_method != 0 && s_method != 2) s_method = 1; if (elite > size) { System.out.print("***error エリートで残す数が多すぎる (S_roul)\n"); System.exit(1); } if (s_method == 2 && s_step <= 0.0) s_step = 1.0; for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; /* 重複個体を削除 */ if (dup_s == 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 && len[i1] == len[i2]) { sw = 0; for (i3 = 0; i3 < len[i1] && 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 || dup_s == 0 && n < size) { System.out.print("***error 残す個体がない (S_roul)\n"); 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++; } } // ルーレット選択 while (count < size+max_ch && k < size) { p = Select(s_method, s_bias, s_step); if (dup_s == 0 && s_w[p] > 0) count++; else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (dup_s == 0 && k < size) { for (i1 = 0; i1 < size+max_ch && k < size; 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(-1); len[k] = len[i1]; pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < len[i1]; i3++) ind[k][i3] = ind[i1][i3]; } } } } } } /*******************/ /* クラスTSPの定義 */ /*******************/ class TSP extends Species { private int max_gen; // 最大世代交代数 private int kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 循環交叉 // =2 : 部分的交叉 // =3 : 順序交叉 // =4 : 一様順序交叉 // =5 : 一様位置交叉 // =6 : エッジ組み替え交叉 // =7 : サブツアー交叉 private double kosa; // 交叉確率 private int k_point; // 交差点の数(負の時は,1から-point間のランダム) private int k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) private int k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private double k_bias; // α,または,method=2の場合は初期値 private double k_step; // β private int mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 移動 // =1 : 逆位 // =2 : スクランブル // =3 : 転座 private double mute; // 突然変異率 private int wd; // 突然変異に使用する部分遺伝子長 private double m_mean; // 摂動の平均値 private double m_std; // 摂動の標準偏差 private int elite; // エリート選択で残す数 private int s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private double s_bias; // α,または,s_method=2の場合は初期値 private double s_step; // β private int out_d; // 表示間隔 private int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) private int out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 private String o_file; // 出力ファイル名 private int n_city; // 都市の数 private int [][] rg; // 都市間の距離 private int kinbo; // 近傍探索(0:行わない,1:行う) private int neib; // 近傍(2 or 3) private int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 private Win wn; // Winオブジェクト int [][] city; //都市の位置データ int display; // 画面表示 // =0 : 画面表示を行わない // =1 : 結果だけを表示 // =2 : 初期状態と結果を表示 // =3 : out_lvlで指定された世代毎に表示 /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : TSP定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ TSP (String name1, String name2, int seed) throws IOException, FileNotFoundException { super (name1, seed); double x, y; int i1, i2; String line; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(name2)); // 基本データの入力 line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); out_lvl = Integer.parseInt(dt.nextToken()); dt.nextToken(); out_m = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); o_file = dt.nextToken(); dt.nextToken(); out_d = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); kosa_m = Integer.parseInt(dt.nextToken()); dt.nextToken(); kosa = Double.parseDouble(dt.nextToken()); dt.nextToken(); k_point = Integer.parseInt(dt.nextToken()); dt.nextToken(); k_vr = Integer.parseInt(dt.nextToken()); dt.nextToken(); k_method = Integer.parseInt(dt.nextToken()); dt.nextToken(); k_bias = Double.parseDouble(dt.nextToken()); dt.nextToken(); k_step = Double.parseDouble(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); mute_m = Integer.parseInt(dt.nextToken()); dt.nextToken(); mute = Double.parseDouble(dt.nextToken()); dt.nextToken(); wd = Integer.parseInt(dt.nextToken()); dt.nextToken(); m_mean = Double.parseDouble(dt.nextToken()); dt.nextToken(); m_std = Double.parseDouble(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); elite = Integer.parseInt(dt.nextToken()); dt.nextToken(); s_method = Integer.parseInt(dt.nextToken()); dt.nextToken(); s_bias = Double.parseDouble(dt.nextToken()); dt.nextToken(); s_step = Double.parseDouble(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); n_city = Integer.parseInt(dt.nextToken()); dt.nextToken(); max_gen = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); kinbo = Integer.parseInt(dt.nextToken()); dt.nextToken(); neib = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); sel = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); display = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); int font = Integer.parseInt(dt.nextToken()); dt.nextToken(); int width = Integer.parseInt(dt.nextToken()); int height = Integer.parseInt(dt.nextToken()); if (kinbo > 0 && neib != 2 && neib != 3) { System.out.print("***error 近傍の値が不適当 \n"); System.exit(1); } if (n_city != max_len) { System.out.print("***error 都市数が不適当 \n"); System.exit(1); } // 都市の位置データ city = new int [n_city][2]; for (i1 = 0; i1 < n_city; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); city[i1][0] = Integer.parseInt(dt.nextToken()); city[i1][1] = Integer.parseInt(dt.nextToken()); } // 距離テーブル rg = new int [n_city][n_city]; for (i1 = 0; i1 < n_city; i1++) { for (i2 = i1+1; i2 < n_city; i2++) { x = city[i2][0] - city[i1][0]; y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(Math.sqrt(x * x + y * y) + 0.5); } } for (i1 = 1; i1 < n_city; i1++) { for (i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } in.close(); // Windowの生成 if (display > 0) wn = new Win (this, font, width, height, n_city); } /**************/ /* 全体の制御 */ /**************/ void Control() throws IOException, FileNotFoundException { int gen = 1, k1; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // 初期集団の発生 Init_std(); // 評価 if (kinbo > 0) Kinbo(); else Adap(); // 画面表示 System.out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); // 初期状態の出力(図) if (display >= 2) { wn.Draw(max, ind[max_n]); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } // 出力 if (Math.abs(out_lvl) > 0) Output(gen); // 世代交代 for (gen = 2; gen <= max_gen; gen++) { // 交叉 switch (kosa_m) { case -1: break; case 0: C_copy(2, max_ch/2, k_method, k_bias, k_step); // 親のコピー break; case 1: C_cycle(kosa, k_method, k_bias, k_step); // 循環交叉 break; case 2: C_part(kosa, k_method, k_bias, k_step); // 部分的交叉 break; case 3: C_seq(kosa, k_method, k_bias, k_step); // 順序交叉 break; case 4: C_useq(kosa, k_method, k_bias, k_step); // 一様順序交叉 break; case 5: C_upos(kosa, k_method, k_bias, k_step); // 一様位置交叉 break; case 6: C_edge(kosa, k_method, k_bias, k_step); // エッジ組み替え交叉 break; case 7: C_sub(kosa, k_point); // サブツアー交叉 break; default: break; } // 突然変異 switch (mute_m) { case -1: break; case 0: M_move(mute); // 移動 break; case 1: M_inv(mute, wd); // 逆位 break; case 2: M_scram(mute, wd); // スクランブル break; case 3: M_chg(mute, wd); // 転座 break; default: break; } // 適応度 if (kinbo > 0) Kinbo(); else Adap(); // 淘汰 S_roul(elite, s_method, s_bias, s_step); // 画面表示 if (gen%out_d == 0) System.out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); // 文字出力と図示 if (Math.abs(out_lvl) > 0) { if (gen%Math.abs(out_lvl) == 0) { if (display == 3) { wn.Draw(max, ind[max_n]); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } Output(gen); } } } gen--; k1 = out_m; out_m = 0; System.out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); if (display >= 1) { wn.Draw(max, ind[max_n]); System.out.println(" 図を確認したらreturnキーを押してください"); in.readLine(); } Output(gen); out_m = k1; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* return : 距離(負) */ /*********************************/ int Kyori(int n_c, int [] p) { int i1, n1, n2, range = 0; n1 = p[0]; for (i1 = 1; i1 < n_c; i1++) { n2 = p[i1]; range -= rg[n1][n2]; n1 = n2; } n2 = p[0]; range -= rg[n1][n2]; return range; } /****************/ /* 適応度の計算 */ /****************/ void Adap() { int i1, k = 0; mean = 0.0; max = 0.0; max_n = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { pi_w[i1] = 2; pi[i1] = Kyori(len[i1], ind[i1]); } if (pi_w[i1] > 0) { k++; mean += pi[i1]; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } if (k > 0) mean /= k; } /**************************************/ /* エッジの入れ替え */ /* n_city : 都市の数 */ /* seq : 訪問する順番 */ /* r_m : 距離の負値 */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ int Change(int n_city, int [] seq, int [] r_m) { int ch = 0, i1, i2, i3, i4, k, k1, k2, max, n1, n2, n3, nn, r, sw = 0; max = r_m[0]; n3 = (int)(rn.nextDouble() * (n_city - 2)); if (n3 > n_city-3) n3 = n_city - 3; // 2近傍 for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { if (n3 == 0) n1 = n_city - 2; else n1 = n_city - 1; for (i2 = n3+2; i2 <= n1 && ch == 0; i2++) { // 枝の場所((n3,n3+1), (k1,k2)) k1 = i2; if (i2 == n_city-1) k2 = 0; else k2 = i2 + 1; // 枝の入れ替え kou1[0] = seq[n3]; k = 1; for (i3 = k1; i3 >= n3+1; i3--) { kou1[k] = seq[i3]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価 r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } } n3++; if (n3 > n_city-3) n3 = 0; } // 3近傍 if (neib == 3 && ch == 0) { for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { n1 = n_city - 2; n2 = n_city - 1; for (i2 = n3+1; i2 <= n1 && ch == 0; i2++) { for (i3 = i2+1; i3 <= n2 && ch == 0; i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3; if (i3 == n_city-1) k2 = 0; else k2 = i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) kou1[0] = seq[n3]; k = 1; for (i4 = i2; i4 >= n3+1; i4--) { kou1[k] = seq[i4]; k++; } for (i4 = k1; i4 >= i2+1; i4--) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その1) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その2) kou1[0] = seq[n3]; k = 1; for (i4 = k1; i4 >= i2+1; i4--) { kou1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その2) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その3) kou1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { kou1[k] = seq[i4]; k++; } for (i4 = i2; i4 >= n3+1; i4--) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その3) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その4) kou1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { kou1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その4) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } } } n3++; if (n3 > n_city-3) n3 = 0; } } // 設定 if (sw > 0) { r_m[0] = max; for (i1 = 0; i1 < n_city; i1++) seq[i1] = kou2[i1]; } return sw; } /**************/ /* 近傍の探索 */ /**************/ void Kinbo() { int i1, k = 0, sw; int r [] = new int [1]; max = 0.0; max_n = -1; mean = 0.0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { pi_w[i1] = 2; sw = 1; r[0] = Kyori(len[i1], ind[i1]); while (sw > 0) sw = Change(len[i1], ind[i1], r); pi[i1] = r[0]; } if (pi_w[i1] > 0) { k++; mean += pi[i1]; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } if (k > 0) mean /= k; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ void Output(int gen) throws IOException, FileNotFoundException { double x, y; int i1, i2, k = 0, n, pr; String now; PrintStream out = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (out_lvl >= 0) { System.out.print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = Integer.parseInt(in.readLine()); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) out = System.out; else { Date newtime = new Date(); // 現在時刻の獲得 now = newtime.toString(); // 文字列への変換 out = new PrintStream(new FileOutputStream(o_file, true)); out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 巡回順序の出力 if (out_m == 0) { for (i1 = 0; i1 < len[max_n]; i1++) { n = ind[max_n][i1]; out.println(n + " " + city[n][0] + " " + city[n][1]); if (pr > 0) { k++; if (k == pr) { in.readLine(); k = 0; } } } } if (pr < 0) out.close(); } } } /*******************/ /* クラスWinの定義 */ /*******************/ class Win extends Frame { double ritu; // 表示倍率 private int font; // フォントサイズ private int min_x, max_x, min_y, max_y; // 都市の存在範囲 private int next, yoyu_x, yoyu_y; // 表示位置 private int n_city; // 都市の数 private int [] seq; // 都市を訪問する順番 private int range; // 距離 private TSP tsp; /*************************************/ /* コンストラクタ */ /* tsp_i : TSPのオブジェクト */ /* city_i : 都市の位置データ */ /* font_i : フォントサイズ */ /* width,height : 表示範囲 */ /* nc : 都市の数 */ /*************************************/ Win (TSP tsp_i, int font_i, int width, int height, int nc) { // Frameクラスのコンストラクタの呼び出し super("巡回セールスマン問題"); // 値の設定と領域の確保 double k1, k2; int i1; tsp = tsp_i; font = font_i; next = 70; yoyu_x = 30; yoyu_y = 80; n_city = nc; seq = new int [n_city]; // 描画領域の計算 min_x = tsp.city[0][0]; max_x = tsp.city[0][0]; min_y = tsp.city[0][1]; max_y = tsp.city[0][1]; for (i1 = 1; i1 < n_city; i1++) { if (tsp.city[i1][0] < min_x) min_x = tsp.city[i1][0]; else { if (tsp.city[i1][0] > max_x) max_x = tsp.city[i1][0]; } if (tsp.city[i1][1] < min_y) min_y = tsp.city[i1][1]; else { if (tsp.city[i1][1] > max_y) max_y = tsp.city[i1][1]; } } k1 = (double)(width - 2 * yoyu_x) / (max_x - min_x); k2 = (double)(height - yoyu_y - yoyu_x) / (max_y - min_y); ritu = (k1 < k2) ? k1 : k2; // ボタンの設定とWindowサイズ // 指定された大きさにWindowサイズを変更 width = 2 * yoyu_x + (int)(ritu * (max_x - min_x)); height = yoyu_y + yoyu_x + (int)(ritu * (max_y - min_y)); setSize(width, height); // ウィンドウを表示 setVisible(true); // イベントアダプタ addWindowListener(new WinEnd()); } /*****************************/ /* 描画指示 */ /* max : 距離の負値 */ /* seq_i : 訪問する順序 */ /*****************************/ void Draw(double max, int [] seq_i) { int i1; range = (int)(-max + 0.5); for (i1 = 0; i1 < n_city; i1++) seq[i1] = seq_i[i1]; repaint(); } /********/ /* 描画 */ /********/ public void paint (Graphics g) { int i1, k, n1, n2, size = 6, x1, x2, y1, y2; Font f; // 距離の表示 f = new Font("TimesRoman", Font.BOLD, 25); g.setFont(f); g.drawString("Length : "+Integer.toString(range), yoyu_x, yoyu_y-30); // 都市番号のフォントサイズ if (font > 0) { f = new Font("TimesRoman", Font.PLAIN, font); g.setFont(f); } // 点と直線のプロット k = size / 2; for (i1 = 0; i1 < n_city; i1++) { n2 = seq[i1]; x2 = yoyu_x + (int)(ritu * (tsp.city[n2][0] - min_x)); y2 = yoyu_y + (int)(ritu * (max_y - tsp.city[n2][1])); g.fillOval(x2, y2, size, size); if (font > 0) g.drawString(Integer.toString(n2), x2+k, y2-k); if (i1 > 0) { n1 = seq[i1-1]; x1 = yoyu_x + (int)(ritu * (tsp.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - tsp.city[n1][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); if (i1 == n_city-1) { n1 = seq[0]; x1 = yoyu_x + (int)(ritu * (tsp.city[n1][0] - min_x)); y1 = yoyu_y + (int)(ritu * (max_y - tsp.city[n1][1])); g.drawLine(x1+k, y1+k, x2+k, y2+k); } } } } /************/ /* 終了処理 */ /************/ class WinEnd extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } } class Test_t { /****************/ /* main program */ /****************/ public static void main(String args[]) throws IOException, FileNotFoundException { int i1, n; String i_file1[], i_file2[], line; TSP tsp; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(args[0])); // 入力ミス if (args.length == 0) { System.out.print("***error ファイル名を入力して下さい\n"); System.exit(1); } // 入力OK else { // 入力データファイル名の入力 n = Integer.parseInt(in.readLine()); i_file1 = new String [n]; i_file2 = new String [n]; for (i1 = 0; i1 < n; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); i_file1[i1] = dt.nextToken(); i_file2[i1] = dt.nextToken(); } in.close(); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { System.out.print("\n+++++ケース " + (i1+1) + "+++++\n"); // 入力と初期設定 tsp = new TSP (i_file1[i1], i_file2[i1], 1000 * i1 + 1234567); // 最適化 tsp.Control(); } } } } //----------------ケーススタディデータ(data_ctj.txt)------ /* 3 data1_tj.txt data2_tj.txt data1_tj.txt data2_tj.txt data1_tj.txt data2_tj.txt */ //---------------Species記述データ(data1_tj.txt)--------- /* 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 */ //---------------TSP記述データ(data2_tj.txt)-------- /* 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 図示(0:しない,1:結果,2:初期状態と結果,3:ステップ) 3 都市番号 0 図の大きさ(幅,高さ) 1000 750 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */
/********************************************************************/ /* f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 */ /* coded by Y.Suganuma */ /********************************************************************/ import java.io.*; import java.util.Random; import java.util.Date; import java.util.StringTokenizer; /***********************/ /* クラスSpeciesの定義 */ /***********************/ class Species { protected double max; // 最大適応度 protected double mean; // 平均適応度 protected double [] pi; // 適応度 protected double [] ro; // ルーレット板 protected int allele_u; // 対立遺伝子上限 protected int allele_l; // 対立遺伝子下限 protected int size; // 個体総数 protected int max_ch; // 子供の数の最大値 protected int max_len; // 最大遺伝子長 protected int min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) protected int max_n; // 最大適応度の個体番号 protected int dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す protected int dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す protected int [][] ind; // 集団(個体の集まり) protected int [] len; // 各個体の遺伝子長 protected int [] kou1; // 交叉・突然変異用作業場所1 protected int [] kou2; // 交叉・突然変異用作業場所2 protected int [] s_w; // 淘汰用指標(選択された回数) protected int [][] edge; // エッジ組み替え交叉用ワークエリア protected byte [] pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) protected Random rn; // 乱数 /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ double norm_d(double m, double s) { double x = 0.0; int i1; for (i1 = 0; i1 < 12; i1++) x += rn.nextDouble(); x = s * (x - 6.0) + m; return x; } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ int Position(int n) { int i1, k = -1, sw = 0; /* 空いている場所を探す */ if (n < 0) { for (i1 = 0; i1 < size+max_ch && k < 0; i1++) { if (pi_w[i1] == 0) k = i1; } if (k < 0) { System.out.print("***error 空いている場所がない --Position--\n"); System.exit(1); } } /* n番目の親(pi_w[i]=2)を捜す */ else { for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] == 2) { k++; if (k == n) { sw = 1; k = i1; } } } } return k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値 */ /* step : β */ /* return : 個体番号 */ /*******************************************************************/ int Select(int method, double bias, double step) { double sum = 0.0, x; int i1, k, min, n, sw; // ルーレット板の用意 switch (method) { // ランダム case -1: n = 0; 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; } break; // 評価値をそのまま利用 case 0: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += pi[i1]; n++; } } if (Math.abs(sum) > 1.0e-10) { sum = 1.0 / Math.abs(sum); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = pi[i1] * sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 最小値からの差 case 1: min = -1; n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { n++; if (min < 0 || pi[i1] < pi[min]) min = i1; } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = pi[i1] - pi[min]; if (ro[i1] < bias) ro[i1] = bias; sum += ro[i1]; } } if (sum > 1.0e-10) { sum = 1.0 / sum; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 線形化 case 2: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = -1.0; n++; } else ro[i1] = 1.0; } sw = 0; sum = bias; while (sw == 0) { min = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (ro[i1] < 0.0 && (min < 0 || pi[i1] < pi[min])) min = i1; } if (min < 0) sw = 1; else { ro[min] = sum; sum += step; } } sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } break; } 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; } /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ Species (String name, int seed) throws IOException, FileNotFoundException { int kind, num; String line; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(name)); /* データの入力 */ line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); allele_u = Integer.parseInt(dt.nextToken()); dt.nextToken(); allele_l = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); max_len = Integer.parseInt(dt.nextToken()); dt.nextToken(); min_len = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); dup_a = Integer.parseInt(dt.nextToken()); dt.nextToken(); dup_s = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); size = Integer.parseInt(dt.nextToken()); dt.nextToken(); max_ch = Integer.parseInt(dt.nextToken()); /* データのチェック */ if (size <= 0) { System.out.print("***error 個体総数≦0 (Constructor)\n"); System.exit(1); } if (max_ch < 0) { System.out.print("***error 子供の数<0 (Constructor)\n"); System.exit(1); } if (max_len <= 0 || min_len == 0) { System.out.print("***error 遺伝子長≦0 (Constructor)\n"); System.exit(1); } if (max_len < min_len) { System.out.print("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n"); System.exit(1); } if (allele_u <= allele_l) { System.out.print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n"); System.exit(1); } kind = allele_u - allele_l + 1; if (dup_a == 0 && max_len > kind) { System.out.print("***error 遺伝子の重複を防ぐことはできない (Constructor)\n"); System.exit(1); } /* 領域の確保 */ num = size + max_ch; ind = new int [num][max_len]; edge = new int [max_len][5]; pi = new double [num]; ro = new double [num]; len = new int [num]; kou1 = new int [max_len]; kou2 = new int [max_len]; s_w = new int [num]; pi_w = new byte [num]; /* 乱数の初期設定 */ rn = new Random (seed); } /********************/ /* 標準的な初期設定 */ /********************/ void Init_std() { int i1, i2, i3, length, lid, 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) { // 遺伝子長の決定 if (min_len < 0) length = max_len; else { length = (int)(rn.nextDouble() * (max_len - min_len + 1) + min_len); if (length > max_len) length = max_len; } len[i1] = length; // 遺伝子の決定 for (i2 = 0; i2 < length; i2++) { sw2 = 0; while (sw2 == 0) { lid = (int)(rn.nextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; ind[i1][i2] = lid; // 重複遺伝子のチェック sw2 = 1; if (dup_a == 0) { for (i3 = 0; i3 < i2 && sw2 > 0; i3++) { if (lid == ind[i1][i3]) sw2 = 0; } } } } // 重複個体のチェック sw1 = 1; if (dup_s == 0) { for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { if (len[i1] == len[i2]) { sw2 = 0; for (i3 = 0; i3 < len[i1] && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ void Out_std(int sw, int out_m, int gen, String name) throws IOException, FileNotFoundException { int i1, i2, k = 0, pr; String now; PrintStream out = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (sw >= 0) { System.out.print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = Integer.parseInt(in.readLine()); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) out = System.out; else { Date newtime = new Date(); // 現在時刻の獲得 now = newtime.toString(); // 文字列への変換 out = new PrintStream(new FileOutputStream(name, true)); out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 詳細出力 for (i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { out.print(i1 + " allele"); for (i2 = 0; i2 < len[i1]; i2++) out.print(" " + ind[i1][i2]); out.println(" value " + pi[i1]); if (pr > 0) { k++; if (k == pr) { in.readLine(); k = 0; } } } } if (pr < 0) out.close(); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数 */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_copy(int method, int pair, int k_method, double k_bias, double k_step) { int i1, i2, i3, k, p, p1, p2 = 0, sw; /* 初期設定とデータチェック */ if (method != 1) method = 2; if (pair <= 0) pair = (method==2) ? max_ch/2 : max_ch; else { if (method == 2 && 2*pair > max_ch || method == 1 && pair > max_ch) { System.out.print("***error 子供が多すぎる (C_copy)\n"); System.exit(1); } } /* 実行 */ for (i1 = 0; i1 < pair; i1++) { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // コピー for (i2 = 0; i2 < method; i2++) { p = (i2 == 0) ? p1 : p2; k = Position(-1); len[k] = len[p]; pi_w[k] = 1; for (i3 = 0; i3 < len[k]; i3++) ind[k][i3] = ind[p][i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数 */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉 */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_point(double kosa, int k_point, int k_vr, int k_method, double k_bias, double k_step) { int abs_p, c1, c2, i1, i2, i3, k1, k2, mn = 0, num, p1, p2 = 0, pair, sw, t11, t12, t21, t22; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { System.out.print("***error 交叉方法が不適当 (C_point)\n"); System.exit(1); } abs_p = Math.abs(k_point); if (abs_p == 0 || abs_p > max_len-1 || min_len > 0 && abs_p > min_len-1) { System.out.print("***error 交叉点の数が不適当 (C_point)\n"); System.exit(1); } if (k_vr > 0 && min_len < 0) { System.out.print("***error 遺伝子長は可変でなければならない (C_point)\n"); System.exit(1); } /* 交叉 */ num = k_point; for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 交叉位置の数の決定 if (k_point < 0) { num = (int)(rn.nextDouble() * abs_p + 1); if (num > abs_p) num = abs_p; } // 交叉位置の決定(点の後ろで交叉) for (i2 = 0; i2 < num; i2++) { // 親1の交叉位置 sw = 0; while (sw == 0) { sw = 1; kou1[i2] = (int)(rn.nextDouble() * (len[p1] - 1)); if (kou1[i2] > len[p1]-2) kou1[i2] = len[p1] - 2; if (k_vr == 0 && kou1[i2] > len[p2]-2) kou1[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou1[i3] == kou1[i2]) sw = 0; } } // 親2の交叉位置 if (k_vr > 0) { sw = 0; while (sw == 0) { sw = 1; kou2[i2] = (int)(rn.nextDouble() * (len[p2] - 1)); if (kou2[i2] > len[p2]-2) kou2[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou2[i3] == kou2[i2]) sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ c1 = 0; c2 = 0; t11 = 0; t21 = 0; // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; for (i2 = 0; i2 < num+1; i2++ ) { // 次の交叉位置を求める if (i2 == num) { // 最後 t12 = len[p1]; t22 = len[p2]; } else { // 親1 t12 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou1[i3] >= 0 && kou1[i3] <= t12) { t12 = kou1[i3]; mn = i3; } } kou1[mn] = -1; t12++; // 親2 if (k_vr == 0) t22 = t12; else { t22 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou2[i3] >= 0 && kou2[i3] <= t22) { t22 = kou2[i3]; mn = i3; } } kou2[mn] = -1; t22++; } } // 指定箇所のコピー for (i3 = t11; i3 < t12; i3++) { if (i2%2 == 0) { if (c1 < max_len) { ind[k1][c1] = ind[p1][i3]; c1++; } } else { if (c2 < max_len) { ind[k2][c2] = ind[p1][i3]; c2++; } } } for (i3 = t21; i3 < t22; i3++) { if (i2%2 == 0) { if (c2 < max_len) { ind[k2][c2] = ind[p2][i3]; c2++; } } else { if (c1 < max_len) { ind[k1][c1] = ind[p2][i3]; c1++; } } } // 交叉位置の移動 t11 = t12; t21 = t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_uniform(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k1, k2, p1, p2 = 0, pair, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a == 0) { System.out.print("***error 交叉方法が不適当 (C_uniform)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_uniform)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; 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]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_mean(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_mean)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < max_ch; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); len[k] = len[p1]; pi_w[k] = 1; // 交叉 for (i2 = 0; i2 < len[k]; i2++) ind[k][i2] = (ind[p1][i2] + ind[p2][i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_cycle(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_cycle)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_cycle)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 初期設定 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = 0; kou2[i2] = 0; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 sw = 0; while (sw == 0) { sw = 1; p = (int)(rn.nextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; if (kou1[p] == 0 && kou2[p] == 0) { kou1[p] = 1; kou2[p] = 1; ind[k1][p] = ind[p1][p]; ind[k2][p] = ind[p2][p]; for (i2 = 0; i2 < len[p1] && sw > 0; i2++) { if (ind[p2][p] == ind[p1][i2]) { ind[k1][i2] = ind[p1][i2]; kou1[i2] = 1; sw = 0; } } sw = 1; for (i2 = 0; i2 < len[p2] && sw > 0; i2++) { if (ind[p1][p] == ind[p2][i2]) { ind[k2][i2] = ind[p2][i2]; kou2[i2] = 1; sw = 0; } } } } sw = 0; i2 = 0; i3 = 0; while (sw == 0) { while (sw == 0 && i2 < len[p1]) { if (kou1[i2] == 0) sw = 1; else i2++; } sw = 0; while (sw == 0 && i3 < len[p2]) { if (kou2[i3] == 0) sw = 1; else i3++; } if (i2 < len[p1] && i3 < len[p2]) { ind[k1][i2] = ind[p2][i3]; ind[k2][i3] = ind[p1][i2]; sw = 0; i2++; i3++; } else sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_part(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, lv, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_part)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_part)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.nextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } for (i2 = p; i2 < len[p1]; i2++) { sw = 0; lv = ind[k1][i2]; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (ind[k2][i2] == ind[k1][i3]) { ind[k1][i2] = ind[k1][i3]; ind[k1][i3] = lv; sw = 1; } } sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (lv == ind[k2][i3]) { ind[k2][i3] = ind[k2][i2]; ind[k2][i2] = lv; sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_seq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, pp, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_seq)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_seq)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.nextDouble() * (len[p1] - 1)); if (p >= len[p1]-1) p = len[p1] - 2; for (i2 = 0; i2 <= p; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } pp = 0; for (i2 = p+1; i2 < len[p1]; i2++) { sw = 0; for (i3 = pp; i3 < len[p2] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4]) { sw = 1; pp = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } pp = 0; for (i2 = p+1; i2 < len[p2]; i2++) { sw = 0; for (i3 = pp; i3 < len[p1] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4]) { sw = 1; pp = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_useq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_useq)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_useq)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; kou1[i2] = (rn.nextDouble() < 0.5) ? 0 : 1; } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p2] && sw == 0; i3++) { for (i4 = 0; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p1] && sw == 0; i3++) { for (i4 = 0; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_upos(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; /* 初期設定とデータのチェック */ pair = max_ch / 2; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_upos)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_upos)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = (rn.nextDouble() < 0.5) ? 0 : 1; if (kou1[i2] > 0) { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p1][i2] == ind[k1][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k1][i3] = ind[p1][i2]; p = i3 + 1; sw = 1; } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { sw = 0; for (i3 = 0; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p2][i2] == ind[k2][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k2][i3] = ind[p2][i2]; p = i3 + 1; sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ void C_edge(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, i5, k, kk, k0 = 0, k1, k2, min, num, p, pair, p1, p2 = 0, sw; int e[] = new int [2]; /* 初期設定とデータのチェック */ pair = max_ch; if (dup_a != 0) { System.out.print("***error 交叉方法が不適当 (C_edge)\n"); System.exit(1); } if (min_len > 0) { System.out.print("***error 遺伝子長は固定長でなければならない (C_edge)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); pi_w[k] = 1; len[k] = len[p1]; // エッジマップの初期化 for (i2 = 0; i2 < len[k]; i2++) { edge[i2][0] = 0; for (i3 = 1; i3 <= 4; i3++) edge[i2][i3] = -1; } // 交叉 // エッジマップの作成 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p1][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p1][len[k]-1]; e[1] = ind[p1][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p1][i3-1]; e[1] = ind[p1][0]; } else { e[0] = ind[p1][i3-1]; e[1] = ind[p1][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p2][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p2][len[k]-1]; e[1] = ind[p2][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p2][i3-1]; e[1] = ind[p2][0]; } else { e[0] = ind[p2][i3-1]; e[1] = ind[p2][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { sw = 1; for (i5 = 1; i5 <= edge[i2][0] && sw == 1; i5++) { if (edge[i2][i5] == e[i4]) sw = 2; } if (sw == 1) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } } } // 交叉の実行 // 出発点の決定 k1 = ind[p1][0]; k2 = ind[p2][0]; if (edge[k1][0] == edge[k2][0]) kk = (rn.nextDouble() > 0.5) ? k2 : k1; else kk = (edge[k1][0] < edge[k2][0]) ? k1 : k2; ind[k][0] = kk; p = 1; while (p < len[k]) { // ノードの除去 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; if (edge[i2][0] > 0) { for (i3 = 1; i3 <= 4 && sw == 0; i3++) { if (edge[i2][i3] == kk) { sw = 1; edge[i2][i3] = -1; edge[i2][0]--; } } } } // 次の現在ノードの選択 min = 10; num = 0; for (i2 = 1; i2 <= 4; i2++) { if (edge[kk][i2] >= 0) { k1 = edge[kk][i2]; if (edge[k1][0] >= 0 && edge[k1][0] < min) { num = 1; min = edge[k1][0]; k0 = k1; } else { if (edge[k1][0] == min) num++; } } } if (num > 1) { k1 = (int)(rn.nextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 1; i2 <= 4 && k0 < 0; i2++) { if (edge[kk][i2] >= 0) { if (edge[edge[kk][i2]][0] == min) { k2++; if (k1 == k2) k0 = edge[kk][i2]; } } } } else { if (num <= 0) { num = 0; for (i2 = 0; i2 < len[k]; i2++) { if (i2 != kk && edge[i2][0] >= 0) num++; } if (num <= 0) { System.out.print("***error invalid data (C_edge)\n"); System.exit(1); } else { k1 = (int)(rn.nextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 0; i2 < len[k] && k0 < 0; i2++) { if (i2 != kk && edge[i2][0] >= 0) { k2++; if (k1 == k2) k0 = i2; } } } } } edge[kk][0] = -1; ind[k][p] = k0; kk = k0; p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数 */ /*************************************************************/ void C_sub(double kosa, int count) { int i1, i2, i3, i4, i5, k1, k2, k3, k4, p1, p2, t11, t12 = 0, t21, t22 = 0, sw; /* 初期設定とデータのチェック */ if ((4*count*size*(size-1)) > max_ch) { System.out.print("***error 子供が多すぎる (C_sub)\n"); System.exit(1); } /* 交叉 */ for (i1 = 0; i1 < size-1; i1++) { // 親1 p1 = Position(i1); if (p1 >= 0) { for (i2 = i1; i2 < size; i2++) { // 親2 p2 = Position(i2); if (p2 >= 0) { // 交叉しない場合 if (rn.nextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 交叉回数の制御 for (i3 = 0; i3 < count; i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 t11 = (int)(rn.nextDouble() * len[p1]); if (t11 > (len[p1]-1)) t11 = len[p1] - 1; sw = 0; while (sw == 0) { t12 = (int)(rn.nextDouble() * len[p1]); if (t12 > (len[p1]-1)) t12 = len[p1] - 1; if (t12 != t11) sw = 1; } if (t11 > t12) { k1 = t11; t11 = t12; t12 = k1; } // 親2の交叉位置 sw = 0; t21 = -1; for (i4 = 0; i4 < len[p2] && t21 < 0; i4++) { for (i5 = t11; i5 <= t12 && t21 < 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) t21 = i4; } } if (t21 >= 0) { t22 = t21 + t12 - t11; if (t22 < len[p2]) { sw = 1; for (i4 = t21+1; i4 <= t22 && sw > 0; i4++) { sw = 0; for (i5 = t11; i5 <= t12 && sw == 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) sw = 1; } } } } // 交叉の実行 if (sw > 0) { k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p1]; k3 = Position(-1); pi_w[k3] = 1; len[k3] = len[p2]; k4 = Position(-1); pi_w[k4] = 1; len[k4] = len[p2]; for (i4 = 0; i4 < t11; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = t11; i4 <= t12; i4++) { ind[k1][i4] = ind[p2][t21+i4-t11]; ind[k2][i4] = ind[p2][t22-i4+t11]; } for (i4 = t12+1; i4 < len[p1]; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = 0; i4 < t21; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } for (i4 = t21; i4 <= t22; i4++) { ind[k3][i4] = ind[p1][t11+i4-t21]; ind[k4][i4] = ind[p1][t12-i4+t21]; } for (i4 = t22+1; i4 < len[p2]; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ void M_alle(double pr) { int i1, i2, lid; /* データのチェックと初期設定 */ if (dup_a == 0) { System.out.print("***error 突然変異方法が不適当 (M_alle)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.nextDouble() <= pr) { lid = (int)(rn.nextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; if (lid != ind[i1][i2]) ind[i1][i2] = lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ void M_move(double pr) { int i1, i2, ld, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 位置の決定 */ // p1 p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p2 sw = 0; while (sw == 0) { p2 = (int)(rn.nextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } /* 実行 */ if (p2 > p1) { ld = ind[i1][p2]; for (i2 = p2; i2 > p1; i2--) ind[i1][i2] = ind[i1][i2-1]; ind[i1][p1] = ld; } else { ld = ind[i1][p2]; for (i2 = p2; i2 < p1-1; i2++) ind[i1][i2] = ind[i1][i2+1]; ind[i1][p1-1] = ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /********************************************************/ void M_inv(double pr, int wd) { int i1, lid, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.nextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.nextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ sw = 0; while (sw == 0) { lid = ind[i1][p1]; ind[i1][p1] = ind[i1][p2]; ind[i1][p2] = lid; p1++; p2--; if (p1 >= p2) sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_scram(double pr, int wd) { int i1, i2, ld, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 区間の決定 */ if (wd == 0) { p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.nextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.nextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } /* 実行 */ for (i2 = p1; i2 <= p2; i2++) { p = (int)(rn.nextDouble() * (p2 - p1 + 1) + p1); if (p > p2) p = p2; ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_chg(double pr, int wd) { int i1, i2, ld, p, p1, p2, p3 = 0, p4, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { /* 区間等の決定([p1,p2]と[p3,p4]の入れ替え) */ // p1 p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.nextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 小さい方をp1,p2にする if (p1 > p3) { p = p1; p1 = p3; p3 = p; } // p4, p2 p4 = (wd == 0) ? (int)(rn.nextDouble() * (len[i1] - p3)) + p3 : p1 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); // 重複部分のチェック if (p2 >= p3) { p = p3 - 1; p3 = p2 + 1; p2 = p; p4 = p3 + (p2 - p1); } /* 実行 */ p = p3; for (i2 = p1; i2 <= p2; i2++) { ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_dup(double pr, int wd) { int i1, i2, p, p1, p2, p3 = 0, p4, sw; /* データのチェック */ if (dup_a == 0) { System.out.print("***error 突然変異方法が不適当 (M_dup)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 p1 = (int)(rn.nextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.nextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 区間を決める if (p3 > p1) { p4 = (wd == 0) ? (int)(rn.nextDouble() * (len[i1] - p3)) + p3 : p3 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); } else { p2 = (wd == 0) ? (int)(rn.nextDouble() * (len[i1] - p1)) + p1 : p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; p4 = p3 + (p2 - p1); } // 実行 p = p4; for (i2 = p2; i2 >= p1; i2--) { ind[i1][p] = ind[i1][i2]; p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布 */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限 */ /* s : 標準偏差または一様分布の上限 */ /******************************************************/ void M_per(double pr, int method, double m, double s) { double w, wd = 0.0, x1; int i1, i2; /* データのチェックと初期設定 */ if (dup_a == 0) { System.out.print("***error 突然変異方法が不適当 (M_per)\n"); System.exit(1); } if (method > 0) wd = s - m; /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.nextDouble() <= pr) { if (method == 0) w = norm_d(m, s); else { w = rn.nextDouble() * wd; if (rn.nextDouble() < 0.5) w = -w; } x1 = (double)ind[i1][i2] + w; if (x1 > allele_u) x1 = allele_u; else { if (x1 < allele_l) x1 = allele_l; } ind[i1][i2] = (int)x1; } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_ins(double pr, int wd) { int i1, i2, l, ld, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { System.out.print("***error 突然変異方法が不適当 (M_ins)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { // 挿入位置の決定 p = (int)(rn.nextDouble() * (len[i1]+1)); if (p > len[i1]) p = len[i1]; // 挿入する遺伝子長の決定 l = (wd == 0) ? (int)(rn.nextDouble() * (max_len - len[i1] + 1)) : wd; if (l > max_len-len[i1]) l = max_len - len[i1]; else { if (l <= 0) l = 1; } // 実行 // 挿入場所の確保 if (p < len[i1]) { for (i2 = len[i1]+l-1; i2 >= p; i2--) ind[i1][i2] = ind[i1][i2-l]; } // 挿入場所の遺伝子の決定 for (i2 = p; i2 < p+l; i2++) { ld = (int)(rn.nextDouble() * (allele_u - allele_l + 1) + allele_l); if (ld > allele_u) ld = allele_u; ind[i1][i2] = ld; } len[i1] += l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ void M_del(double pr, int wd) { int i1, i2, l, max, p; /* データのチェック */ if (dup_a == 0 || min_len < 0) { System.out.print("***error 突然変異方法が不適当 (M_del)\n"); System.exit(1); } /* 実行 */ for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.nextDouble() <= pr) { // 削除位置の決定 p = (int)(rn.nextDouble() * len[i1]); if (p >= len[i1]) p = len[i1] - 1; // 削除する遺伝子長の決定 max = (len[i1]-min_len < len[i1]-p) ? len[i1] - min_len : len[i1] - p; l = (wd == 0) ? (int)(rn.nextDouble() * max + 1) : wd; if (l > max) l = max; // 実行 for (i2 = 0; i2 < len[i1]-p-l; i2++) ind[i1][p+i2] = ind[i1][p+i2+l]; len[i1] -= l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ void S_roul(int elite, int s_method, double s_bias, double s_step) { int count = 0, i1, i2, i3, k = 0, max, n = 0, p, sw; /* 値のチェックと初期設定 */ if (s_method != 0 && s_method != 2) s_method = 1; if (elite > size) { System.out.print("***error エリートで残す数が多すぎる (S_roul)\n"); System.exit(1); } if (s_method == 2 && s_step <= 0.0) s_step = 1.0; for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; /* 重複個体を削除 */ if (dup_s == 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 && len[i1] == len[i2]) { sw = 0; for (i3 = 0; i3 < len[i1] && 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 || dup_s == 0 && n < size) { System.out.print("***error 残す個体がない (S_roul)\n"); 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++; } } // ルーレット選択 while (count < size+max_ch && k < size) { p = Select(s_method, s_bias, s_step); if (dup_s == 0 && s_w[p] > 0) count++; else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (dup_s == 0 && k < size) { for (i1 = 0; i1 < size+max_ch && k < size; 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(-1); len[k] = len[i1]; pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < len[i1]; i3++) ind[k][i3] = ind[i1][i3]; } } } } } } /************************/ /* クラスFunctionの定義 */ /************************/ class Function extends Species { private double cv; // 2進数を10進数の変換する係数 private int max_gen; // 最大世代交代数 private int kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 多点交叉 // =2 : 一様交叉 // =3 : 平均化交叉 private double kosa; // 交叉確率 private int k_point; // 交差点の数(負の時は,1から-point間のランダム) private int k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) private int k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private double k_bias; // α,または,method=2の場合は初期値 private double k_step; // β private int mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 対立遺伝子への置換 // =1 : 移動 // =2 : 逆位 // =3 : スクランブル // =4 : 転座 // =5 : 重複 // =6 : 摂動 private double mute; // 突然変異率 private int wd; // 突然変異に使用する部分遺伝子長 private double m_mean; // 摂動の平均値 private double m_std; // 摂動の標準偏差 private int elite; // エリート選択で残す数 private int s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private double s_bias; // α,または,s_method=2の場合は初期値 private double s_step; // β private int out_d; // 表示間隔 private int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) private int out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 private String o_file; // 出力ファイル名 /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : Function定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ Function (String name1, String name2, int seed) throws IOException, FileNotFoundException { super (name1, seed); String line; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(name2)); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); out_lvl = Integer.parseInt(dt.nextToken()); dt.nextToken(); out_m = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); o_file = dt.nextToken(); dt.nextToken(); out_d = Integer.parseInt(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); kosa_m = Integer.parseInt(dt.nextToken()); dt.nextToken(); kosa = Double.parseDouble(dt.nextToken()); dt.nextToken(); k_point = Integer.parseInt(dt.nextToken()); dt.nextToken(); k_vr = Integer.parseInt(dt.nextToken()); dt.nextToken(); k_method = Integer.parseInt(dt.nextToken()); dt.nextToken(); k_bias = Double.parseDouble(dt.nextToken()); dt.nextToken(); k_step = Double.parseDouble(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); mute_m = Integer.parseInt(dt.nextToken()); dt.nextToken(); mute = Double.parseDouble(dt.nextToken()); dt.nextToken(); wd = Integer.parseInt(dt.nextToken()); dt.nextToken(); m_mean = Double.parseDouble(dt.nextToken()); dt.nextToken(); m_std = Double.parseDouble(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); elite = Integer.parseInt(dt.nextToken()); dt.nextToken(); s_method = Integer.parseInt(dt.nextToken()); dt.nextToken(); s_bias = Double.parseDouble(dt.nextToken()); dt.nextToken(); s_step = Double.parseDouble(dt.nextToken()); line = in.readLine(); dt = new StringTokenizer(line, " "); dt.nextToken(); max_gen = Integer.parseInt(dt.nextToken()); cv = 1.0 / (Math.pow(2.0, (double)max_len) - 1.0); in.close(); } /**************/ /* 全体の制御 */ /**************/ void Control() throws IOException, FileNotFoundException { int gen = 1, k1; // 初期集団の発生 Init_std(); // 評価 Adap(); // 出力 System.out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); if (Math.abs(out_lvl) > 0) Output(gen); // 世代交代 for (gen = 2; gen <= max_gen; gen++) { // 交叉 switch (kosa_m) { case -1: break; case 0: C_copy(2, max_ch/2, k_method, k_bias, k_step); // 親のコピー break; case 1: C_point(kosa, k_point, k_vr, k_method, k_bias, k_step); // 多点交叉 break; case 2: C_uniform(kosa, k_method, k_bias, k_step); // 一様交叉 break; case 3: C_mean(kosa, k_method, k_bias, k_step); // 平均化交叉 break; default: break; } // 突然変異 switch (mute_m) { case -1: break; case 0: M_alle(mute); // 対立遺伝子への置換 break; case 1: M_move(mute); // 移動 break; case 2: M_inv(mute, wd); // 逆位 break; case 3: M_scram(mute, wd); // スクランブル break; case 4: M_chg(mute, wd); // 転座 break; case 5: M_dup(mute, wd); // 重複 break; case 6: M_per(mute, wd, m_mean, m_std); // 摂動 break; default: break; } // 適応度 Adap(); // 淘汰 S_roul(elite, s_method, s_bias, s_step); // 出力 if (gen%out_d == 0) System.out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); if (Math.abs(out_lvl) > 0) { if (gen%Math.abs(out_lvl) == 0) Output(gen); } } gen--; k1 = out_m; out_m = 0; System.out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); Output(gen); out_m = k1; } /****************/ /* 適応度の計算 */ /****************/ void Adap() { double x, y; int i1, i2, n = 0; max = 0.0; max_n = -1; mean = 0.0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { x = 0.0; y = 0.0; for (i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += Math.pow(2.0, y); y += 1.0; } x *= cv; pi[i1] = Math.sin(3.0*x) + 0.5 * Math.sin(9.0*x) + Math.sin(15.0*x+50.0); pi_w[i1] = 2; } if (pi_w[i1] > 0) { mean += pi[i1]; n++; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } mean /= n; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ void Output(int gen) throws IOException, FileNotFoundException { double x, y; int i1, i2, k = 0, pr; String now; PrintStream out = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (out_lvl >= 0) { System.out.print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = Integer.parseInt(in.readLine()); } else pr = -1; if (pr != 0) { // 出力先の決定と評価値の出力 if (pr > 0) out = System.out; else { Date newtime = new Date(); // 現在時刻の獲得 now = newtime.toString(); // 文字列への変換 out = new PrintStream(new FileOutputStream(o_file, true)); out.println("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 詳細出力 for (i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { out.print(i1 + " allele"); for (i2 = 0; i2 < len[i1]; i2++) out.print(" " + ind[i1][i2]); x = 0.0; y = 0.0; for (i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += Math.pow(2.0, y); y += 1.0; } x *= cv; out.println(" x " + x + " y " + pi[i1]); if (pr > 0) { k++; if (k == pr) { in.readLine(); k = 0; } } } } if (pr < 0) out.close(); } } } public class Test_f { /****************/ /* main program */ /****************/ public static void main(String args[]) throws IOException, FileNotFoundException { int i1, n; String i_file1[], i_file2[], line; Function fn; StringTokenizer dt; BufferedReader in = new BufferedReader(new FileReader(args[0])); // 入力ミス if (args.length == 0) { System.out.print("***error ファイル名を入力して下さい\n"); System.exit(1); } // 入力OK else { // 入力データファイル名の入力 n = Integer.parseInt(in.readLine()); i_file1 = new String [n]; i_file2 = new String [n]; for (i1 = 0; i1 < n; i1++) { line = in.readLine(); dt = new StringTokenizer(line, " "); i_file1[i1] = dt.nextToken(); i_file2[i1] = dt.nextToken(); } in.close(); // 実行(乱数の初期値を変える) for (i1 = 0; i1 < n; i1++) { System.out.print("\n+++++ケース " + (i1+1) + "+++++\n"); // 入力と初期設定 fn = new Function (i_file1[i1], i_file2[i1], 1000 * i1 + 1234567); // 最適化 fn.Control(); } } } } //------------------ケーススタディデータ(data_cf.txt)------ /* 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt */ //------------------Species記述データ(data1_f.txt)--------- /* 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 */ //------------------Function記述データ(data2_f.txt)-------- /* 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 */
<?php /***********************************/ /* 遺伝的アルゴリズムによるTSPの解 */ /* coded by Y.Suganuma */ /***********************************/ /***********************/ /* クラスSpeciesの定義 */ /***********************/ class Species { protected $max; // 最大適応度 protected $mean; // 平均適応度 protected $pi; // 適応度 protected $ro; // ルーレット板 protected $allele_u; // 対立遺伝子上限 protected $allele_l; // 対立遺伝子下限 protected $size; // 個体総数 protected $max_ch; // 子供の数の最大値 protected $max_len; // 最大遺伝子長 protected $min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) protected $max_n; // 最大適応度の個体番号 protected $dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す protected $dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す protected $ind; // 集団(個体の集まり) protected $len; // 各個体の遺伝子長 protected $kou1; // 交叉・突然変異用作業場所1 protected $kou2; // 交叉・突然変異用作業場所2 protected $s_w; // 淘汰用指標(選択された回数) protected $edge; // エッジ組み替え交叉用ワークエリア protected $pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ function Species($name, $seed) { /* データの入力 */ $in = fopen($name, "rb"); fscanf($in, "%*s %d %*s %d", $this->allele_u, $this->allele_l); fscanf($in, "%*s %d %*s %d", $this->max_len, $this->min_len); fscanf($in, "%*s %d %*s %d", $this->dup_a, $this->dup_s); fscanf($in, "%*s %d %*s %d", $this->size, $this->max_ch); /* データのチェック */ if ($this->size <= 0) exit("***error 個体総数≦0 (Constructor)\n"); if ($this->max_ch < 0) exit("***error 子供の数<0 (Constructor)\n"); if ($this->max_len <= 0 || $this->min_len == 0) exit("***error 遺伝子長≦0 (Constructor)\n"); if ($this->max_len < $this->min_len) exit("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n"); if ($this->allele_u <= $this->allele_l) exit("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n"); $kind = $this->allele_u - $this->allele_l + 1; if ($this->dup_a == 0 && $this->max_len > $kind) exit("***error 遺伝子の重複を防ぐことはできない (Constructor)\n"); /* 領域の確保 */ $num = $this->size + $this->max_ch; $this->ind = array($num); for ($i1 = 0; $i1 < $num; $i1++) $this->ind[$i1] = array($this->max_len); $this->edge = array($this->max_len); for ($i1 = 0; $i1 < $this->max_len; $i1++) $this->edge[$i1] = array(5); $this->pi = array($num); $this->ro = array($num); $this->len = array($num); $this->kou1 = array($this->max_len); $this->kou2 = array($this->max_len); $this->s_w = array($num); $this->pi_w = array($num); /* 乱数の初期設定 */ mt_srand($seed); } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ function Position($n) { $k = -1; $sw = 0; /* 空いている場所を探す */ if ($n < 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch && $k < 0; $i1++) { if ($this->pi_w[$i1] == 0) $k = $i1; } if ($k < 0) exit("***error 空いている場所がない --Position--\n"); } /* n番目の親($this->pi_w[i]=2)を捜す */ else { for ($i1 = 0; $i1 < $this->size+$this->max_ch && $sw == 0; $i1++) { if ($this->pi_w[$i1] == 2) { $k++; if ($k == $n) { $sw = 1; $k = $i1; } } } } return $k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値(default=0) */ /* step : β(default=1) */ /* return : 個体番号 */ /*******************************************************************/ function Select($method = -1, $bias = 0.0, $step = 1.0) { $sum = 0.0; // ルーレット板の用意 switch ($method) { // ランダム case -1: $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $n++; } $sum = 1.0 / $n; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $sum; } break; // 評価値をそのまま利用 case 0: $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $sum += $this->pi[$i1]; $n++; } } if (abs($sum) > 1.0e-10) { $sum = 1.0 / abs($sum); for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $this->pi[$i1] * $sum; } } else { $sum = 1.0 / $n; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $sum; } } break; // 最小値からの差 case 1: $min = -1; $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $n++; if ($min < 0 || $this->pi[$i1] < $this->pi[$min]) $min = $i1; } } for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $this->ro[$i1] = $this->pi[$i1] - $this->pi[$min]; if ($this->ro[$i1] < $bias) $this->ro[$i1] = $bias; $sum += $this->ro[$i1]; } } if ($sum > 1.0e-10) { $sum = 1.0 / $sum; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] *= $sum; } } else { $sum = 1.0 / $n; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $sum; } } break; // 線形化 case 2: $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $this->ro[$i1] = -1.0; $n++; } else $this->ro[$i1] = 1.0; } $sw = 0; $sum = $bias; while ($sw == 0) { $min = -1; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->ro[$i1] < 0.0 && ($min < 0 || $this->pi[$i1] < $this->pi[$min])) $min = $i1; } if ($min < 0) $sw = 1; else { $this->ro[$min] = $sum; $sum += $step; } } $sum = 1.0 / (0.5 * (2.0 * $bias + $step * ($n - 1)) * $n); for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] *= $sum; } break; } $sum = 0.0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $sum += $this->ro[$i1]; $this->ro[$i1] = $sum; } } // 選択 $x = uniform(); $sw = 0; $k = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch && $sw == 0; $i1++) { if ($this->pi_w[$i1] > 1) { if ($x <= $this->ro[$i1]) { $sw = 1; $k = $i1; } } } return $k; } /********************/ /* 標準的な初期設定 */ /********************/ function Init_std() { /* 初期設定 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($i1 < $this->size) $this->pi_w[$i1] = 1; // 適応度の計算前 else $this->pi_w[$i1] = 0; // 未使用 } /* 遺伝子の決定 */ for ($i1 = 0; $i1 < $this->size; $i1++) { $sw1 = 0; while ($sw1 == 0) { // 遺伝子長の決定 if ($this->min_len < 0) $length = $this->max_len; else { $length = intval(uniform() * ($this->max_len - $this->min_len + 1) + $this->min_len); if ($length > $this->max_len) $length = $this->max_len; } $this->len[$i1] = $length; // 遺伝子の決定 for ($i2 = 0; $i2 < $length; $i2++) { $sw2 = 0; while ($sw2 == 0) { $lid = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l); if ($lid > $this->allele_u) $lid = $this->allele_u; $this->ind[$i1][$i2] = $lid; // 重複遺伝子のチェック $sw2 = 1; if ($this->dup_a == 0) { for ($i3 = 0; $i3 < $i2 && $sw2 > 0; $i3++) { if ($lid == $this->ind[$i1][$i3]) $sw2 = 0; } } } } // 重複個体のチェック $sw1 = 1; if ($this->dup_s == 0) { for ($i2 = 0; $i2 < $i1 && $sw1 > 0; $i2++) { if ($this->len[$i1] == $this->len[$i2]) { $sw2 = 0; for ($i3 = 0; $i3 < $this->len[$i1] && $sw2 == 0; $i3++) { if ($this->ind[$i1][$i3] != $this->ind[$i2][$i3]) $sw2 = 1; } if ($sw2 == 0) $sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ function Out_std($sw, $out_m, $gen, $name) { $k = 0; if ($sw >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); fscanf(STDIN, "%d", $pr); } else $pr = -1; if ($pr != 0) { // 出力先の決定と評価値の出力 if ($pr > 0) { $out = STDOUT; fgets(STDIN); } else { $x = getdate(); $now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒"; $out = fopen($name, "ab"); fwrite($out, "***世代 ".$gen." 適応度 max ".$this->max." (".$this->max_n.") mean ".$this->mean." 時間 ".$now."\n"); } // 詳細出力 for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if (($this->pi_w[$i1] > 1) && ($out_m == 0 || $out_m == 1 && $i1 == $this->max_n)) { $str = $i1." allele"; for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) $str += " ".$this->ind[$i1][$i2]; $str += " value ".$this->pi[$i1]; fwrite($out, $str."\n"); if ($pr > 0) { $k++; if ($k == $pr) { fgets(STDIN); $k = 0; } } } } if ($pr < 0) fclose($out); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供)(default) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数(default=max_ch/2) */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_copy($method = 2, $pair = 0, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータチェック */ if ($method != 1) $method = 2; if ($pair <= 0) $pair = ($method==2) ? intval($this->max_ch/2) : $this->max_ch; else { if ($method == 2 && 2*$pair > $this->max_ch || $method == 1 && $pair > $this->max_ch) exit("***error 子供が多すぎる (C_copy)\n"); } /* 実行 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // コピー for ($i2 = 0; $i2 < $method; $i2++) { $p = ($i2 == 0) ? $p1 : $p2; $k = $this->Position(-1); $this->len[$k] = $this->len[$p]; $this->pi_w[$k] = 1; for ($i3 = 0; $i3 < $this->len[$k]; $i3++) $this->ind[$k][$i3] = $this->ind[$p][$i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数(default=1) */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉(default) */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_point($kosa, $k_point = 1, $k_vr = 0, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { $mn = 0; /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a == 0) exit("***error 交叉方法が不適当 (C_point)\n"); $abs_p = abs($k_point); if ($abs_p == 0 || $abs_p > $this->max_len-1 || $this->min_len > 0 && $abs_p > $this->min_len-1) exit("***error 交叉点の数が不適当 (C_point)\n"); if ($k_vr > 0 && $this->min_len < 0) exit("***error 遺伝子長は可変でなければならない (C_point)\n"); /* 交叉 */ $num = $k_point; for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 交叉位置の数の決定 if ($k_point < 0) { $num = intval(uniform() * $abs_p + 1); if ($num > $abs_p) $num = $abs_p; } // 交叉位置の決定(点の後ろで交叉) for ($i2 = 0; $i2 < $num; $i2++) { // 親1の交叉位置 $sw = 0; while ($sw == 0) { $sw = 1; $this->kou1[$i2] = intval(uniform() * ($this->len[$p1] - 1)); if ($this->kou1[$i2] > $this->len[$p1]-2) $this->kou1[$i2] = $this->len[$p1] - 2; if ($k_vr == 0 && $this->kou1[$i2] > $this->len[$p2]-2) $this->kou1[$i2] = $this->len[$p2] - 2; for ($i3 = 0; $i3 < $i2 && $sw > 0; $i3++) { if ($this->kou1[$i3] == $this->kou1[$i2]) $sw = 0; } } // 親2の交叉位置 if ($k_vr > 0) { $sw = 0; while ($sw == 0) { $sw = 1; $this->kou2[$i2] = intval(uniform() * ($this->len[$p2] - 1)); if ($this->kou2[$i2] > $this->len[$p2]-2) $this->kou2[$i2] = $this->len[$p2] - 2; for ($i3 = 0; $i3 < $i2 && $sw > 0; $i3++) { if ($this->kou2[$i3] == $this->kou2[$i2]) $sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ $c1 = 0; $c2 = 0; $t11 = 0; $t21 = 0; // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; for ($i2 = 0; $i2 < $num+1; $i2++ ) { // 次の交叉位置を求める if ($i2 == $num) { // 最後 $t12 = $this->len[$p1]; $t22 = $this->len[$p2]; } else { // 親1 $t12 = $this->max_len; for ($i3 = 0; $i3 < $num; $i3++) { if ($this->kou1[$i3] >= 0 && $this->kou1[$i3] <= $t12) { $t12 = $this->kou1[$i3]; $mn = $i3; } } $this->kou1[$mn] = -1; $t12++; // 親2 if ($k_vr == 0) $t22 = $t12; else { $t22 = $this->max_len; for ($i3 = 0; $i3 < $num; $i3++) { if ($this->kou2[$i3] >= 0 && $this->kou2[$i3] <= $t22) { $t22 = $this->kou2[$i3]; $mn = $i3; } } $this->kou2[$mn] = -1; $t22++; } } // 指定箇所のコピー for ($i3 = $t11; $i3 < $t12; $i3++) { if ($i2%2 == 0) { if ($c1 < $this->max_len) { $this->ind[$k1][$c1] = $this->ind[$p1][$i3]; $c1++; } } else { if ($c2 < $this->max_len) { $this->ind[$k2][$c2] = $this->ind[$p1][$i3]; $c2++; } } } for ($i3 = $t21; $i3 < $t22; $i3++) { if ($i2%2 == 0) { if ($c2 < $this->max_len) { $this->ind[$k2][$c2] = $this->ind[$p2][$i3]; $c2++; } } else { if ($c1 < $this->max_len) { $this->ind[$k1][$c1] = $this->ind[$p2][$i3]; $c1++; } } } // 交叉位置の移動 $t11 = $t12; $t21 = $t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_uniform($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a == 0) exit("***error 交叉方法が不適当 (C_uniform)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_uniform)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { if (uniform() > 0.5) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; } else { $this->ind[$k1][$i2] = $this->ind[$p2][$i2]; $this->ind[$k2][$i2] = $this->ind[$p1][$i2]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_mean($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_mean)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $this->max_ch; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(1, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k = $this->Position(-1); $this->len[$k] = $this->len[$p1]; $this->pi_w[$k] = 1; // 交叉 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) $this->ind[$k][$i2] = ($this->ind[$p1][$i2] + $this->ind[$p2][$i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_cycle($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_cycle)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_cycle)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 初期設定 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->kou1[$i2] = 0; $this->kou2[$i2] = 0; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 $sw = 0; while ($sw == 0) { $sw = 1; $p = intval(uniform() * $this->len[$p1]); if ($p >= $this->len[$p1]) $p = $this->len[$p1] - 1; if ($this->kou1[$p] == 0 && $this->kou2[$p] == 0) { $this->kou1[$p] = 1; $this->kou2[$p] = 1; $this->ind[$k1][$p] = $this->ind[$p1][$p]; $this->ind[$k2][$p] = $this->ind[$p2][$p]; for ($i2 = 0; $i2 < $this->len[$p1] && $sw > 0; $i2++) { if ($this->ind[$p2][$p] == $this->ind[$p1][$i2]) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->kou1[$i2] = 1; $sw = 0; } } $sw = 1; for ($i2 = 0; $i2 < $this->len[$p2] && $sw > 0; $i2++) { if ($this->ind[$p1][$p] == $this->ind[$p2][$i2]) { $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; $this->kou2[$i2] = 1; $sw = 0; } } } } $sw = 0; $i2 = 0; $i3 = 0; while ($sw == 0) { while ($sw == 0 && $i2 < $this->len[$p1]) { if ($this->kou1[$i2] == 0) $sw = 1; else $i2++; } $sw = 0; while ($sw == 0 && $i3 < $this->len[$p2]) { if ($this->kou2[$i3] == 0) $sw = 1; else $i3++; } if ($i2 < $this->len[$p1] && $i3 < $this->len[$p2]) { $this->ind[$k1][$i2] = $this->ind[$p2][$i3]; $this->ind[$k2][$i3] = $this->ind[$p1][$i2]; $sw = 0; $i2++; $i3++; } else $sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_part($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_part)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_part)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 $p = intval(uniform() * $this->len[$p1]); if ($p >= $this->len[$p1]) $p = $this->len[$p1] - 1; for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; } for ($i2 = $p; $i2 < $this->len[$p1]; $i2++) { $sw = 0; $lv = $this->ind[$k1][$i2]; for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($this->ind[$k2][$i2] == $this->ind[$k1][$i3]) { $this->ind[$k1][$i2] = $this->ind[$k1][$i3]; $this->ind[$k1][$i3] = $lv; $sw = 1; } } $sw = 0; for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($lv == $this->ind[$k2][$i3]) { $this->ind[$k2][$i3] = $this->ind[$k2][$i2]; $this->ind[$k2][$i2] = $lv; $sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_seq($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_seq)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_seq)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 $p = intval(uniform() * ($this->len[$p1] - 1)); if ($p >= $this->len[$p1]-1) $p = $this->len[$p1] - 2; for ($i2 = 0; $i2 <= $p; $i2++) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; } $pp = 0; for ($i2 = $p+1; $i2 < $this->len[$p1]; $i2++) { $sw = 0; for ($i3 = $pp; $i3 < $this->len[$p2] && $sw == 0; $i3++) { for ($i4 = $p+1; $i4 < $this->len[$p1] && $sw == 0; $i4++) { if ($this->ind[$p2][$i3] == $this->ind[$p1][$i4]) { $sw = 1; $pp = $i3 + 1; $this->ind[$k1][$i2] = $this->ind[$p1][$i4]; } } } } $pp = 0; for ($i2 = $p+1; $i2 < $this->len[$p2]; $i2++) { $sw = 0; for ($i3 = $pp; $i3 < $this->len[$p1] && $sw == 0; $i3++) { for ($i4 = $p+1; $i4 < $this->len[$p2] && $sw == 0; $i4++) { if ($this->ind[$p1][$i3] == $this->ind[$p2][$i4]) { $sw = 1; $pp = $i3 + 1; $this->ind[$k2][$i2] = $this->ind[$p2][$i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_useq($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_useq)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_useq)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; $this->kou1[$i2] = (uniform() < 0.5) ? 0 : 1; } $p = 0; for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { if ($this->kou1[$i2] > 0) { $sw = 0; for ($i3 = $p; $i3 < $this->len[$p2] && $sw == 0; $i3++) { for ($i4 = 0; $i4 < $this->len[$p1] && $sw == 0; $i4++) { if ($this->ind[$p2][$i3] == $this->ind[$p1][$i4] && $this->kou1[$i4] > 0) { $sw = 1; $p = $i3 + 1; $this->ind[$k1][$i2] = $this->ind[$p1][$i4]; } } } } } $p = 0; for ($i2 = 0; $i2 < $this->len[$p2]; $i2++) { if ($this->kou1[$i2] > 0) { $sw = 0; for ($i3 = $p; $i3 < $this->len[$p1] && $sw == 0; $i3++) { for ($i4 = 0; $i4 < $this->len[$p2] && $sw == 0; $i4++) { if ($this->ind[$p1][$i3] == $this->ind[$p2][$i4] && $this->kou1[$i4] > 0) { $sw = 1; $p = $i3 + 1; $this->ind[$k2][$i2] = $this->ind[$p2][$i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_upos($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_upos)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_upos)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->kou1[$i2] = (uniform() < 0.5) ? 0 : 1; if ($this->kou1[$i2] > 0) { $this->ind[$k1][$i2] = $this->ind[$p2][$i2]; $this->ind[$k2][$i2] = $this->ind[$p1][$i2]; } } $p = 0; for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($this->kou1[$i3] > 0 && $this->ind[$p1][$i2] == $this->ind[$k1][$i3]) $sw = 1; } if ($sw == 0) { for ($i3 = $p; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($this->kou1[$i3] == 0) { $this->ind[$k1][$i3] = $this->ind[$p1][$i2]; $p = $i3 + 1; $sw = 1; } } } } $p = 0; for ($i2 = 0; $i2 < $this->len[$p2]; $i2++) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$p2] && $sw == 0; $i3++) { if ($this->kou1[$i3] > 0 && $this->ind[$p2][$i2] == $this->ind[$k2][$i3]) $sw = 1; } if ($sw == 0) { for ($i3 = $p; $i3 < $this->len[$p2] && $sw == 0; $i3++) { if ($this->kou1[$i3] == 0) { $this->ind[$k2][$i3] = $this->ind[$p2][$i2]; $p = $i3 + 1; $sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_edge($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { $e = array(2); $k0 = 0; /* 初期設定とデータのチェック */ $pair = $this->max_ch; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_edge)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_edge)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(1, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k = $this->Position(-1); $this->pi_w[$k] = 1; $this->len[$k] = $this->len[$p1]; // エッジマップの初期化 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { $this->edge[$i2][0] = 0; for ($i3 = 1; $i3 <= 4; $i3++) $this->edge[$i2][$i3] = -1; } // 交叉 // エッジマップの作成 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$k] && $sw == 0; $i3++) { if ($i2 == $this->ind[$p1][$i3]) { $sw = 1; if ($i3 == 0) { $e[0] = $this->ind[$p1][$this->len[$k]-1]; $e[1] = $this->ind[$p1][1]; } else { if ($i3 == $this->len[$k]-1) { $e[0] = $this->ind[$p1][$i3-1]; $e[1] = $this->ind[$p1][0]; } else { $e[0] = $this->ind[$p1][$i3-1]; $e[1] = $this->ind[$p1][$i3+1]; } } for ($i4 = 0; $i4 < 2; $i4++) { $this->edge[$i2][0]++; $this->edge[$i2][$this->edge[$i2][0]] = $e[$i4]; } } } $sw = 0; for ($i3 = 0; $i3 < $this->len[$k] && $sw == 0; $i3++) { if ($i2 == $this->ind[$p2][$i3]) { $sw = 1; if ($i3 == 0) { $e[0] = $this->ind[$p2][$this->len[$k]-1]; $e[1] = $this->ind[$p2][1]; } else { if ($i3 == $this->len[$k]-1) { $e[0] = $this->ind[$p2][$i3-1]; $e[1] = $this->ind[$p2][0]; } else { $e[0] = $this->ind[$p2][$i3-1]; $e[1] = $this->ind[$p2][$i3+1]; } } for ($i4 = 0; $i4 < 2; $i4++) { $sw = 1; for ($i5 = 1; $i5 <= $this->edge[$i2][0] && $sw == 1; $i5++) { if ($this->edge[$i2][$i5] == $e[$i4]) $sw = 2; } if ($sw == 1) { $this->edge[$i2][0]++; $this->edge[$i2][$this->edge[$i2][0]] = $e[$i4]; } } } } } // 交叉の実行 // 出発点の決定 $k1 = $this->ind[$p1][0]; $k2 = $this->ind[$p2][0]; if ($this->edge[$k1][0] == $this->edge[$k2][0]) $kk = (uniform() > 0.5) ? $k2 : $k1; else $kk = ($this->edge[$k1][0] < $this->edge[$k2][0]) ? $k1 : $k2; $this->ind[$k][0] = $kk; $p = 1; while ($p < $this->len[$k]) { // ノードの除去 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { $sw = 0; if ($this->edge[$i2][0] > 0) { for ($i3 = 1; $i3 <= 4 && $sw == 0; $i3++) { if ($this->edge[$i2][$i3] == $kk) { $sw = 1; $this->edge[$i2][$i3] = -1; $this->edge[$i2][0]--; } } } } // 次の現在ノードの選択 $min = 10; $num = 0; for ($i2 = 1; $i2 <= 4; $i2++) { if ($this->edge[$kk][$i2] >= 0) { $k1 = $this->edge[$kk][$i2]; if ($this->edge[$k1][0] >= 0 && $this->edge[$k1][0] < $min) { $num = 1; $min = $this->edge[$k1][0]; $k0 = $k1; } else { if ($this->edge[$k1][0] == $min) $num++; } } } if ($num > 1) { $k1 = intval(uniform() * $num) + 1; if ($k1 > $num) $k1 = $num; $k2 = 0; $k0 = -1; for ($i2 = 1; $i2 <= 4 && $k0 < 0; $i2++) { if ($this->edge[$kk][$i2] >= 0) { if ($this->edge[$this->edge[$kk][$i2]][0] == $min) { $k2++; if ($k1 == $k2) $k0 = $this->edge[$kk][$i2]; } } } } else { if ($num <= 0) { $num = 0; for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { if ($i2 != $kk && $this->edge[$i2][0] >= 0) $num++; } if ($num <= 0) exit("***error invalid data (C_edge)\n"); else { $k1 = intval(uniform() * $num) + 1; if ($k1 > $num) $k1 = $num; $k2 = 0; $k0 = -1; for ($i2 = 0; $i2 < $this->len[$k] && $k0 < 0; $i2++) { if ($i2 != $kk && $this->edge[$i2][0] >= 0) { $k2++; if ($k1 == $k2) $k0 = $i2; } } } } } $this->edge[$kk][0] = -1; $this->ind[$k][$p] = $k0; $kk = $k0; $p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数(default=10) */ /*************************************************************/ function C_sub($kosa, $count = 10) { $t22 = 0; /* 初期設定とデータのチェック */ if ((4*$count*$this->size*($this->size-1)) > $this->max_ch) exit("***error 子供が多すぎる (C_sub)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $this->size-1; $i1++) { // 親1 $p1 = $this->Position($i1); if ($p1 >= 0) { for ($i2 = $i1; $i2 < $this->size; $i2++) { // 親2 $p2 = $this->Position($i2); if ($p2 >= 0) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 交叉回数の制御 for ($i3 = 0; $i3 < $count; $i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 $t11 = intval(uniform() * $this->len[$p1]); if ($t11 > ($this->len[$p1]-1)) $t11 = $this->len[$p1] - 1; $sw = 0; while ($sw == 0) { $t12 = intval(uniform() * $this->len[$p1]); if ($t12 > ($this->len[$p1]-1)) $t12 = $this->len[$p1] - 1; if ($t12 != $t11) $sw = 1; } if ($t11 > $t12) { $k1 = $t11; $t11 = $t12; $t12 = $k1; } // 親2の交叉位置 $sw = 0; $t21 = -1; for ($i4 = 0; $i4 < $this->len[$p2] && $t21 < 0; $i4++) { for ($i5 = $t11; $i5 <= $t12 && $t21 < 0; $i5++) { if ($this->ind[$p2][$i4] == $this->ind[$p1][$i5]) $t21 = $i4; } } if ($t21 >= 0) { $t22 = $t21 + $t12 - $t11; if ($t22 < $this->len[$p2]) { $sw = 1; for ($i4 = $t21+1; $i4 <= $t22 && $sw > 0; $i4++) { $sw = 0; for ($i5 = $t11; $i5 <= $t12 && $sw == 0; $i5++) { if ($this->ind[$p2][$i4] == $this->ind[$p1][$i5]) $sw = 1; } } } } // 交叉の実行 if ($sw > 0) { $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p1]; $k3 = $this->Position(-1); $this->pi_w[$k3] = 1; $this->len[$k3] = $this->len[$p2]; $k4 = $this->Position(-1); $this->pi_w[$k4] = 1; $this->len[$k4] = $this->len[$p2]; for ($i4 = 0; $i4 < $t11; $i4++) { $this->ind[$k1][$i4] = $this->ind[$p1][$i4]; $this->ind[$k2][$i4] = $this->ind[$p1][$i4]; } for ($i4 = $t11; $i4 <= $t12; $i4++) { $this->ind[$k1][$i4] = $this->ind[$p2][$t21+$i4-$t11]; $this->ind[$k2][$i4] = $this->ind[$p2][$t22-$i4+$t11]; } for ($i4 = $t12+1; $i4 < $this->len[$p1]; $i4++) { $this->ind[$k1][$i4] = $this->ind[$p1][$i4]; $this->ind[$k2][$i4] = $this->ind[$p1][$i4]; } for ($i4 = 0; $i4 < $t21; $i4++) { $this->ind[$k3][$i4] = $this->ind[$p2][$i4]; $this->ind[$k4][$i4] = $this->ind[$p2][$i4]; } for ($i4 = $t21; $i4 <= $t22; $i4++) { $this->ind[$k3][$i4] = $this->ind[$p1][$t11+$i4-$t21]; $this->ind[$k4][$i4] = $this->ind[$p1][$t12-$i4+$t21]; } for ($i4 = $t22+1; $i4 < $this->len[$p2]; $i4++) { $this->ind[$k3][$i4] = $this->ind[$p2][$i4]; $this->ind[$k4][$i4] = $this->ind[$p2][$i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ function M_alle($pr) { /* データのチェックと初期設定 */ if ($this->dup_a == 0) exit("***error 突然変異方法が不適当 (M_alle)\n"); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) { if (uniform() <= $pr) { $lid = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l); if ($lid > $this->allele_u) $lid = $this->allele_u; if ($lid != $this->ind[$i1][$i2]) $this->ind[$i1][$i2] = $lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ function M_move($pr) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 位置の決定 */ // p1 $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; // p2 $sw = 0; while ($sw == 0) { $p2 = intval(uniform() * $this->len[$i1]); if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; if ($p2 != $p1) $sw = 1; } /* 実行 */ if ($p2 > $p1) { $ld = $this->ind[$i1][$p2]; for ($i2 = $p2; $i2 > $p1; $i2--) $this->ind[$i1][$i2] = $this->ind[$i1][$i2-1]; $this->ind[$i1][$p1] = $ld; } else { $ld = $this->ind[$i1][$p2]; for ($i2 = $p2; $i2 < $p1-1; $i2++) $this->ind[$i1][$i2] = $this->ind[$i1][$i2+1]; $this->ind[$i1][$p1-1] = $ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /********************************************************/ function M_inv($pr, $wd = 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 区間の決定 */ if ($wd == 0) { $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; $sw = 0; while ($sw == 0) { $p2 = intval(uniform() * $this->len[$i1]); if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; if ($p2 != $p1) $sw = 1; } if ($p1 > $p2) { $p = $p1; $p1 = $p2; $p2 = $p; } } else { $p1 = $this->len[$i1]; while ($p1 > $this->len[$i1]-2) $p1 = intval(uniform() * $this->len[$i1]); $p2 = $p1 + $wd - 1; if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; } /* 実行 */ $sw = 0; while ($sw == 0) { $lid = $this->ind[$i1][$p1]; $this->ind[$i1][$p1] = $this->ind[$i1][$p2]; $this->ind[$i1][$p2] = $lid; $p1++; $p2--; if ($p1 >= $p2) $sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_scram($pr, $wd = 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 区間の決定 */ if ($wd == 0) { $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; $sw = 0; while ($sw == 0) { $p2 = intval(uniform() * $this->len[$i1]); if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; if ($p2 != $p1) $sw = 1; } if ($p1 > $p2) { $p = $p1; $p1 = $p2; $p2 = $p; } } else { $p1 = $this->len[$i1]; while ($p1 > $this->len[$i1]-2) $p1 = intval(uniform() * $this->len[$i1]); $p2 = $p1 + $wd - 1; if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; } /* 実行 */ for ($i2 = $p1; $i2 <= $p2; $i2++) { $p = intval(uniform() * ($p2 - $p1 + 1) + $p1); if ($p > $p2) $p = $p2; $ld = $this->ind[$i1][$i2]; $this->ind[$i1][$i2] = $this->ind[$i1][$p]; $this->ind[$i1][$p] = $ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_chg($pr, $wd = 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 区間等の決定([p1,p2]と[p3,p4]の入れ替え) */ // p1 $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; // p3 $sw = 0; while ($sw == 0) { $p3 = intval(uniform() * $this->len[$i1]); if ($p3 >= $this->len[$i1]) $p3 = $this->len[$i1] - 1; if ($p3 != $p1) $sw = 1; } // 小さい方をp1,p2にする if ($p1 > $p3) { $p = $p1; $p1 = $p3; $p3 = $p; } // p4, p2 $p4 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p3)) + $p3 : $p1 + $wd - 1; if ($p4 >= $this->len[$i1]) $p4 = $this->len[$i1] - 1; $p2 = $p1 + ($p4 - $p3); // 重複部分のチェック if ($p2 >= $p3) { $p = $p3 - 1; $p3 = $p2 + 1; $p2 = $p; $p4 = $p3 + ($p2 - $p1); } /* 実行 */ $p = $p3; for ($i2 = $p1; $i2 <= $p2; $i2++) { $ld = $this->ind[$i1][$i2]; $this->ind[$i1][$i2] = $this->ind[$i1][$p]; $this->ind[$i1][$p] = $ld; $p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(deafult) */ /**********************************************************************/ function M_dup($pr, $wd = 0) { /* データのチェック */ if ($this->dup_a == 0) exit("***error 突然変異方法が不適当 (M_dup)\n"); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; // p3 $sw = 0; while ($sw == 0) { $p3 = intval(uniform() * $this->len[$i1]); if ($p3 >= $this->len[$i1]) $p3 = $this->len[$i1] - 1; if ($p3 != $p1) $sw = 1; } // 区間を決める if ($p3 > $p1) { $p4 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p3)) + $p3 : $p3 + $wd - 1; if ($p4 >= $this->len[$i1]) $p4 = $this->len[$i1] - 1; $p2 = $p1 + ($p4 - $p3); } else { $p2 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p1)) + $p1 :$p1 + $wd - 1; if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; $p4 = $p3 + ($p2 - $p1); } // 実行 $p = $p4; for ($i2 = $p2; $i2 >= $p1; $i2--) { $this->ind[$i1][$p] = $this->ind[$i1][$i2]; $p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布(default) */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限(default=0.0) */ /* s : 標準偏差または一様分布の上限(default=1.0) */ /******************************************************/ function M_per($pr, $method = 0, $m = 0.0, $s = 1.0) { $wd = 0.0; /* データのチェックと初期設定 */ if ($this->dup_a == 0) exit("***error 突然変異方法が不適当 (M_per)\n"); if ($method > 0) $wd = $s - $m; /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) { if (uniform() <= $pr) { if ($method == 0) $w = norm_d($m, $s); else { $w = uniform() * $wd; if (uniform() < 0.5) $w = -$w; } $x1 = (double)$this->ind[$i1][$i2] + $w; if ($x1 > $this->allele_u) $x1 = $this->allele_u; else { if ($x1 < $this->allele_l) $x1 = $this->allele_l; } $this->ind[$i1][$i2] = intval($x1); } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_ins($pr, $wd = 0) { /* データのチェック */ if ($this->dup_a == 0 || $this->min_len < 0) exit("***error 突然変異方法が不適当 (M_ins)\n"); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { // 挿入位置の決定 $p = intval(uniform() * ($this->len[$i1]+1)); if ($p > $this->len[$i1]) $p = $this->len[$i1]; // 挿入する遺伝子長の決定 $l = ($wd == 0) ? intval(uniform() * ($this->max_len - $this->len[$i1] + 1)) : $wd; if ($l > $this->max_len-$this->len[$i1]) $l = $this->max_len - $this->len[$i1]; else { if ($l <= 0) $l = 1; } // 実行 // 挿入場所の確保 if ($p < $this->len[$i1]) { for ($i2 = $this->len[$i1]+$l-1; $i2 >= $p; $i2--) $this->ind[$i1][$i2] = $this->ind[$i1][$i2-$l]; } // 挿入場所の遺伝子の決定 for ($i2 = $p; $i2 < $p+$l; $i2++) { $ld = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l); if ($ld > $this->allele_u) $ld = $this->allele_u; $this->ind[$i1][$i2] = $ld; } $this->len[$i1] += $l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_del($pr, $wd = 0) { /* データのチェック */ if ($this->dup_a == 0 || $this->min_len < 0) exit("***error 突然変異方法が不適当 (M_del)\n"); exit(1); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { // 削除位置の決定 $p = intval(uniform() * $this->len[$i1]); if ($p >= $this->len[$i1]) $p = $this->len[$i1] - 1; // 削除する遺伝子長の決定 $max = ($this->len[$i1]-$this->min_len < $this->len[$i1]-$p) ? $this->len[$i1] - $this->min_len : $this->len[$i1] - $p; $l = ($wd == 0) ? intval(uniform() * $max + 1) : $wd; if ($l > $max) $l = $max; // 実行 for ($i2 = 0; $i2 < $this->len[$i1]-$p-$l; $i2++) $this->ind[$i1][$p+$i2] = $this->ind[$i1][$p+$i2+$l]; $this->len[$i1] -= $l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ function S_roul($elite = 0, $s_method = 1, $s_bias = 0.0, $s_step = 1.0) { $count = 0; $k = 0; $n = 0; /* 値のチェックと初期設定 */ if ($s_method != 0 && $s_method != 2) $s_method = 1; if ($elite > $this->size) exit("***error エリートで残す数が多すぎる (S_roul)\n"); if ($s_method == 2 && $s_step <= 0.0) $s_step = 1.0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) $this->s_w[$i1] = 0; /* 重複個体を削除 */ if ($this->dup_s == 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 0) { for ($i2 = $i1+1; $i2 < $this->size+$this->max_ch; $i2++) { if ($this->pi_w[$i2] > 0 && $this->len[$i1] == $this->len[$i2]) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$i1] && $sw == 0; $i3++) { if ($this->ind[$i1][$i3] != $this->ind[$i2][$i3]) $sw = 1; } if ($sw == 0) $this->pi_w[$i2] = 0; } } } } } for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $n++; } if ($n < 0 || $this->dup_s == 0 && $n < $this->size) exit("***error 残す個体がない (S_roul)\n"); /* 淘汰して残す個体を選ぶ */ // エリートの選択 $sw = 0; while ($k < $elite && $k < $n && $sw == 0) { $max = -1; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1 && $this->s_w[$i1] == 0) { if ($max < 0 || $this->pi[$i1] > $this->pi[$max]) $max = $i1; } } if ($max < 0) $sw = 1; else { $this->s_w[$max] = 1; $k++; } } // ルーレット選択 while ($count < $this->size+$this->max_ch && $k < $this->size) { $p = $this->Select($s_method, $s_bias, $s_step); if ($this->dup_s == 0 && $this->s_w[$p] > 0) $count++; else { $count = 0; $this->s_w[$p]++; $k++; } } // 選択に失敗した場合の処理 if ($this->dup_s == 0 && $k < $this->size) { for ($i1 = 0; $i1 < $this->size+$this->max_ch && $k < $this->size; $i1++) { if ($this->pi_w[$i1] > 1 && $this->s_w[$i1] == 0) { $this->s_w[$i1] = 1; $k++; } } } // 複数回選択されたものの処理 for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->s_w[$i1] == 0) $this->pi_w[$i1] = 0; } for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->s_w[$i1] > 0) { if ($this->s_w[$i1] > 1) { for ($i2 = 2; $i2 <= $this->s_w[$i1]; $i2++) { $k = $this->Position(-1); $this->len[$k] = $this->len[$i1]; $this->pi_w[$k] = 2; $this->pi[$k] = $this->pi[$i1]; for ($i3 = 0; $i3 < $this->len[$i1]; $i3++) $this->ind[$k][$i3] = $this->ind[$i1][$i3]; } } } } } } /***********************************/ /* [0, 1] 区間の一様分布変量の発生 */ /***********************************/ function uniform() { return mt_rand() / mt_getrandmax(); } /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ function norm_d($m, $s) { $x = 0.0; for ($i1 = 0; $i1 < 12; $i1++) $x += uniform(); $x = $s * ($x - 6.0) + $m; return $x; } /*******************/ /* クラスTSPの定義 */ /*******************/ class TSP extends Species { private $max_gen; // 最大世代交代数 private $kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 循環交叉 // =2 : 部分的交叉 // =3 : 順序交叉 // =4 : 一様順序交叉 // =5 : 一様位置交叉 // =6 : エッジ組み替え交叉 // =7 : サブツアー交叉 private $kosa; // 交叉確率 private $k_point; // 交差点の数(負の時は,1から-k_point間のランダム) private $k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) private $k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private $k_bias; // α,または,method=2の場合は初期値 private $k_step; // β private $mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 移動 // =1 : 逆位 // =2 : スクランブル // =3 : 転座 private $mute; // 突然変異率 private $wd; // 突然変異に使用する部分遺伝子長 private $m_mean; // 摂動の平均値 private $m_std; // 摂動の標準偏差 private $elite; // エリート選択で残す数 private $s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private $s_bias; // α,または,s_method=2の場合は初期値 private $s_step; // β private $out_d; // 表示間隔 private $out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) private $out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 private $o_file; // 出力ファイル名 private $city; //都市の位置データ private $n_city; // 都市の数 private $rg; // 都市間の距離 private $kinbo; // 近傍探索(0:行わない,1:行う) private $neib; // 近傍(2 or 3) private $sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : TSP定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ function TSP ($name1, $name2, $seed) { parent::Species($name1, $seed); // 基本データの入力 $in = fopen($name2, "r"); fscanf($in, "%*s %d %*s %d", $this->out_lvl, $this->out_m); fscanf($in, "%*s %s %*s %d", $this->o_file, $this->out_d); fscanf($in, "%*s %d %*s %lf %*s %d %*s %d %*s %d %*s %lf %*s %lf", $this->kosa_m, $this->kosa, $this->k_point, $this->k_vr, $this->k_method, $this->k_bias, $this->k_step); fscanf($in, "%*s %d %*s %lf %*s %d %*s %lf %*s %lf", $this->mute_m, $this->mute, $this->wd, $this->m_mean, $this->m_stds); fscanf($in, "%*s %d %*s %d %*s %lf %*s %lf", $this->elite, $this->s_method, $this->s_bias, $this->s_step); fscanf($in, "%*s %d %*s %d", $this->n_city, $this->max_gen); fscanf($in, "%*s %d %*s %d", $this->kinbo, $this->neib); fscanf($in, "%*s %d", $this->sel); if ($this->kinbo > 0 && $this->neib != 2 && $this->neib != 3) exit("***error 近傍の値が不適当 \n"); if ($this->n_city != $this->max_len) exit("***error 都市数が不適当 \n"); // 都市の位置データ $this->city = array($this->n_city); for ($i1 = 0; $i1 < $this->n_city; $i1++) { $this->city[$i1] = array(2); fscanf($in, "%d %d", $this->city[$i1][0], $this->city[$i1][1]); } // 距離テーブル $this->rg = array($this->n_city); for ($i1 = 0; $i1 < $this->n_city; $i1++) { $this->rg[$i1] = array($this->n_city); for ($i2 = $i1+1; $i2 < $this->n_city; $i2++) { $x = $this->city[$i2][0] - $this->city[$i1][0]; $y = $this->city[$i2][1] - $this->city[$i1][1]; $this->rg[$i1][$i2] = round(sqrt($x * $x + $y * $y)); } } for ($i1 = 1; $i1 < $this->n_city; $i1++) { for ($i2 = 0; $i2 < $i1; $i2++) $this->rg[$i1][$i2] = $this->rg[$i2][$i1]; } fclose($in); } /**************/ /* 全体の制御 */ /**************/ function Control() { $gen = 1; // 初期集団の発生 $this->Init_std(); // 評価 if ($this->kinbo > 0) $this->Kinbo(); else $this->Adap(); // 出力 printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean); if (abs($this->out_lvl) > 0) $this->Output($gen); // 世代交代 for ($gen = 2; $gen <= $this->max_gen; $gen++) { // 交叉 switch ($this->kosa_m) { case -1: break; case 0: $this->C_copy(); // 親のコピー break; case 1: $this->C_cycle($this->kosa); // 循環交叉 break; case 2: $this->C_part($this->kosa); // 部分的交叉 break; case 3: $this->C_seq($this->kosa); // 順序交叉 break; case 4: $this->C_useq($this->kosa); // 一様順序交叉 break; case 5: $this->C_upos($this->kosa); // 一様位置交叉 break; case 6: $this->C_edge($this->kosa); // エッジ組み替え交叉 break; case 7: $this->C_sub($this->kosa, $this->k_point); // サブツアー交叉 break; default: break; } // 突然変異 switch ($this->mute_m) { case -1: break; case 0: $this->M_move($this->mute); // 移動 break; case 1: $this->M_inv($this->mute); // 逆位 break; case 2: $this->M_scram($this->mute); // スクランブル break; case 3: $this->M_chg($this->mute); // 転座 break; default: break; } // 適応度 if ($this->kinbo > 0) $this->Kinbo(); else $this->Adap(); // 淘汰 $this->S_roul($this->elite); // 出力 if ($gen%$this->out_d == 0) printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean); if (abs($this->out_lvl) > 0) { if ($gen%abs($this->out_lvl) == 0) $this->Output($gen); } } $gen--; $k1 = $this->out_m; $this->out_m = 0; printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean); $this->Output($gen); $this->out_m = $k1; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* return : 距離(負) */ /*********************************/ function Kyori($n_c, $p) { $range = 0; $n1 = $p[0]; for ($i1 = 1; $i1 < $n_c; $i1++) { $n2 = $p[$i1]; $range -= $this->rg[$n1][$n2]; $n1 = $n2; } $n2 = $p[0]; $range -= $this->rg[$n1][$n2]; return $range; } /****************/ /* 適応度の計算 */ /****************/ function Adap() { $k = 0; $this->mean = 0.0; $this->max = 0.0; $this->max_n = -1; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { $this->pi_w[$i1] = 2; $this->pi[$i1] = $this->Kyori($this->len[$i1], $this->ind[$i1]); } if ($this->pi_w[$i1] > 0) { $k++; $this->mean += $this->pi[$i1]; if ($this->max_n < 0 || $this->pi[$i1] > $this->max) { $this->max = $this->pi[$i1]; $this->max_n = $i1; } } } if ($k > 0) $this->mean /= $k; } /**************************************/ /* エッジの入れ替え */ /* n_city : 都市の数 */ /* seq : 訪問する順番 */ /* r_m : 距離の負値 */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ function Change($n_city, &$seq, &$r_m) { $ch = 0; $sw = 0; $max = $r_m; $n3 = intval(uniform() * ($n_city - 2)); if ($n3 > $n_city-3) $n3 = $n_city - 3; // 2近傍 for ($i1 = 0; $i1 <= $n_city-3 && $ch == 0; $i1++) { if ($n3 == 0) $n1 = $n_city - 2; else $n1 = $n_city - 1; for ($i2 = $n3+2; $i2 <= $n1 && $ch == 0; $i2++) { // 枝の場所((n3,n3+1), (k1,k2)) $k1 = $i2; if ($i2 == $n_city-1) $k2 = 0; else $k2 = $i2 + 1; // 枝の入れ替え $this->kou1[0] = $seq[$n3]; $k = 1; for ($i3 = $k1; $i3 >= $n3+1; $i3--) { $this->kou1[$k] = $seq[$i3]; $k++; } $nn = $k2; while ($nn != $n3) { $this->kou1[$k] = $seq[$nn]; $k++; $nn++; if ($nn > $n_city-1) $nn = 0; } // 評価 $r = $this->Kyori($n_city, $this->kou1); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $n_city; $i3++) $this->kou2[$i3] = $this->kou1[$i3]; if ($this->sel > 0) $ch = 1; } } $n3++; if ($n3 > $n_city-3) $n3 = 0; } // 3近傍 if ($this->neib == 3 && $ch == 0) { for ($i1 = 0; $i1 <= $n_city-3 && $ch == 0; $i1++) { $n1 = $n_city - 2; $n2 = $n_city - 1; for ($i2 = $n3+1; $i2 <= $n1 && $ch == 0; $i2++) { for ($i3 = $i2+1; $i3 <= $n2 && $ch == 0; $i3++) { // 枝の場所((n3,n3+1), ($i2,$i2+1), (k1,k2)) $k1 = $i3; if ($i3 == $n_city-1) $k2 = 0; else $k2 = $i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) $this->kou1[0] = $seq[$n3]; $k = 1; for ($i4 = $i2; $i4 >= $n3+1; $i4--) { $this->kou1[$k] = $seq[$i4]; $k++; } for ($i4 = $k1; $i4 >= $i2+1; $i4--) { $this->kou1[$k] = $seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->kou1[$k] = $seq[$nn]; $k++; $nn++; if ($nn > $n_city-1) $nn = 0; } // 評価(その1) $r = $this->Kyori($n_city, $this->kou1); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $n_city; $i3++) $this->kou2[$i3] = $this->kou1[$i3]; if ($this->sel > 0) $ch = 1; } // 入れ替え(その2) $this->kou1[0] = $seq[$n3]; $k = 1; for ($i4 = $k1; $i4 >= $i2+1; $i4--) { $this->kou1[$k] = $seq[$i4]; $k++; } for ($i4 = $n3+1; $i4 <= $i2; $i4++) { $this->kou1[$k] = $seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->kou1[$k] = $seq[$nn]; $k++; $nn++; if ($nn > $n_city-1) $nn = 0; } // 評価(その2) $r = $this->Kyori($n_city, $this->kou1); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $n_city; $i3++) $this->kou2[$i3] = $this->kou1[$i3]; if ($this->sel > 0) $ch = 1; } // 入れ替え(その3) $this->kou1[0] = $seq[$n3]; $k = 1; for ($i4 = $i2+1; $i4 <= $k1; $i4++) { $this->kou1[$k] = $seq[$i4]; $k++; } for ($i4 = $i2; $i4 >= $n3+1; $i4--) { $this->kou1[$k] = $seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->kou1[$k] = $seq[$nn]; $k++; $nn++; if ($nn > $n_city-1) $nn = 0; } // 評価(その3) $r = $this->Kyori($n_city, $this->kou1); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $n_city; $i3++) $this->kou2[$i3] = $this->kou1[$i3]; if ($this->sel > 0) $ch = 1; } // 入れ替え(その4) $this->kou1[0] = $seq[$n3]; $k = 1; for ($i4 = $i2+1; $i4 <= $k1; $i4++) { $this->kou1[$k] = $seq[$i4]; $k++; } for ($i4 = $n3+1; $i4 <= $i2; $i4++) { $this->kou1[$k] = $seq[$i4]; $k++; } $nn = $k2; while ($nn != $n3) { $this->kou1[$k] = $seq[$nn]; $k++; $nn++; if ($nn > $n_city-1) $nn = 0; } // 評価(その4) $r = $this->Kyori($n_city, $this->kou1); if ($r > $max) { $max = $r; $sw = 1; for ($i3 = 0; $i3 < $n_city; $i3++) $this->kou2[$i3] = $this->kou1[$i3]; if ($this->sel > 0) $ch = 1; } } } $n3++; if ($n3 > $n_city-3) $n3 = 0; } } // 設定 if ($sw > 0) { $r_m = $max; for ($i1 = 0; $i1 < $n_city; $i1++) $seq[$i1] = $this->kou2[$i1]; } return $sw; } /**************/ /* 近傍の探索 */ /**************/ function Kinbo() { $k = 0; $this->max = 0.0; $this->max_n = -1; $this->mean = 0.0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { $this->pi_w[$i1] = 2; $sw = 1; $r = $this->Kyori($this->len[$i1], $this->ind[$i1]); while ($sw > 0) $sw = $this->Change($this->len[$i1], $this->ind[$i1], $r); $this->pi[$i1] = $r; } if ($this->pi_w[$i1] > 0) { $k++; $this->mean += $this->pi[$i1]; if ($this->max_n < 0 || $this->pi[$i1] > $this->max) { $this->max = $this->pi[$i1]; $this->max_n = $i1; } } } if ($k > 0) $this->mean /= $k; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ function Output($gen) { $k = 0; if ($this->out_lvl >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); fscanf(STDIN, "%d", $pr); } else $pr = -1; if ($pr != 0) { // 出力先の決定と評価値の出力 if ($pr > 0) { $out = STDOUT; fgets(STDIN); } else { $x = getdate(); $now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒"; $out = fopen($this->o_file, "ab"); fwrite($out, "***世代 ".$gen." 適応度 max ".$this->max." (".$this->max_n.") mean ".$this->mean." 時間 ".$now."\n"); } // 巡回順序の出力 if ($this->out_m == 0) { for ($i1 = 0; $i1 < $this->len[$this->max_n]; $i1++) { $n = $this->ind[$this->max_n][$i1]; fwrite($out, $n." ".$this->city[$n][0]." ".$this->city[$n][1]."\n"); if ($pr > 0) { $k++; if ($k == $pr) { fgets(STDIN); $k = 0; } } } } if ($pr < 0) fclose($out); } } } /****************/ /* main program */ /****************/ // 入力ミス if (count($argv) <= 1) exit("***error ファイル名を入力して下さい\n"); // 入力OK else { // ファイルのオープン $in = fopen($argv[1], "rb"); if ($in == NULL) exit("***error ファイル名が不適当です\n"); // 入力データファイル名の入力 fscanf($in, "%d", $n); // データの数 $seed = array($n); $i_file1 = array($n); $i_file2 = array($n); for ($i1 = 0; $i1 < $n; $i1++) { $seed[$i1] = 1000 * $i1 + 1234567; fscanf($in, "%s %s", $i_file1[$i1], $i_file2[$i1]); } fclose($in); // 実行(乱数の初期値を変える) for ($i1 = 0; $i1 < $n; $i1++) { printf("\n+++++ケース %d+++++\n", $i1+1); $tsp = new TSP($i_file1[$i1], $i_file2[$i1], $seed[$i1]); $tsp->Control(); } } //----------------ケーススタディデータ(data_ct.txt)------ /* 3 data1_t.txt data2_t.txt data1_t.txt data2_t.txt data1_t.txt data2_t.txt */ //---------------Species記述データ(data1_t.txt)--------- /* 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 */ //---------------TSP記述データ(data2_t.txt)-------- /* 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */ ?>
<?php /********************************************************************/ /* f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 */ /* coded by Y.Suganuma */ /********************************************************************/ /***********************/ /* クラスSpeciesの定義 */ /***********************/ class Species { protected $max; // 最大適応度 protected $mean; // 平均適応度 protected $pi; // 適応度 protected $ro; // ルーレット板 protected $allele_u; // 対立遺伝子上限 protected $allele_l; // 対立遺伝子下限 protected $size; // 個体総数 protected $max_ch; // 子供の数の最大値 protected $max_len; // 最大遺伝子長 protected $min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) protected $max_n; // 最大適応度の個体番号 protected $dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す protected $dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す protected $ind; // 集団(個体の集まり) protected $len; // 各個体の遺伝子長 protected $kou1; // 交叉・突然変異用作業場所1 protected $kou2; // 交叉・突然変異用作業場所2 protected $s_w; // 淘汰用指標(選択された回数) protected $edge; // エッジ組み替え交叉用ワークエリア protected $pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ function Species($name, $seed) { /* データの入力 */ $in = fopen($name, "rb"); fscanf($in, "%*s %d %*s %d", $this->allele_u, $this->allele_l); fscanf($in, "%*s %d %*s %d", $this->max_len, $this->min_len); fscanf($in, "%*s %d %*s %d", $this->dup_a, $this->dup_s); fscanf($in, "%*s %d %*s %d", $this->size, $this->max_ch); /* データのチェック */ if ($this->size <= 0) exit("***error 個体総数≦0 (Constructor)\n"); if ($this->max_ch < 0) exit("***error 子供の数<0 (Constructor)\n"); if ($this->max_len <= 0 || $this->min_len == 0) exit("***error 遺伝子長≦0 (Constructor)\n"); if ($this->max_len < $this->min_len) exit("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n"); if ($this->allele_u <= $this->allele_l) exit("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n"); $kind = $this->allele_u - $this->allele_l + 1; if ($this->dup_a == 0 && $this->max_len > $kind) exit("***error 遺伝子の重複を防ぐことはできない (Constructor)\n"); /* 領域の確保 */ $num = $this->size + $this->max_ch; $this->ind = array($num); for ($i1 = 0; $i1 < $num; $i1++) $this->ind[$i1] = array($this->max_len); $this->edge = array($this->max_len); for ($i1 = 0; $i1 < $this->max_len; $i1++) $this->edge[$i1] = array(5); $this->pi = array($num); $this->ro = array($num); $this->len = array($num); $this->kou1 = array($this->max_len); $this->kou2 = array($this->max_len); $this->s_w = array($num); $this->pi_w = array($num); /* 乱数の初期設定 */ mt_srand($seed); } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ function Position($n) { $k = -1; $sw = 0; /* 空いている場所を探す */ if ($n < 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch && $k < 0; $i1++) { if ($this->pi_w[$i1] == 0) $k = $i1; } if ($k < 0) exit("***error 空いている場所がない --Position--\n"); } /* n番目の親($this->pi_w[i]=2)を捜す */ else { for ($i1 = 0; $i1 < $this->size+$this->max_ch && $sw == 0; $i1++) { if ($this->pi_w[$i1] == 2) { $k++; if ($k == $n) { $sw = 1; $k = $i1; } } } } return $k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値(default=0) */ /* step : β(default=1) */ /* return : 個体番号 */ /*******************************************************************/ function Select($method = -1, $bias = 0.0, $step = 1.0) { $sum = 0.0; // ルーレット板の用意 switch ($method) { // ランダム case -1: $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $n++; } $sum = 1.0 / $n; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $sum; } break; // 評価値をそのまま利用 case 0: $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $sum += $this->pi[$i1]; $n++; } } if (abs($sum) > 1.0e-10) { $sum = 1.0 / abs($sum); for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $this->pi[$i1] * $sum; } } else { $sum = 1.0 / $n; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $sum; } } break; // 最小値からの差 case 1: $min = -1; $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $n++; if ($min < 0 || $this->pi[$i1] < $this->pi[$min]) $min = $i1; } } for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $this->ro[$i1] = $this->pi[$i1] - $this->pi[$min]; if ($this->ro[$i1] < $bias) $this->ro[$i1] = $bias; $sum += $this->ro[$i1]; } } if ($sum > 1.0e-10) { $sum = 1.0 / $sum; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] *= $sum; } } else { $sum = 1.0 / $n; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] = $sum; } } break; // 線形化 case 2: $n = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $this->ro[$i1] = -1.0; $n++; } else $this->ro[$i1] = 1.0; } $sw = 0; $sum = $bias; while ($sw == 0) { $min = -1; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->ro[$i1] < 0.0 && ($min < 0 || $this->pi[$i1] < $this->pi[$min])) $min = $i1; } if ($min < 0) $sw = 1; else { $this->ro[$min] = $sum; $sum += $step; } } $sum = 1.0 / (0.5 * (2.0 * $bias + $step * ($n - 1)) * $n); for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $this->ro[$i1] *= $sum; } break; } $sum = 0.0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) { $sum += $this->ro[$i1]; $this->ro[$i1] = $sum; } } // 選択 $x = uniform(); $sw = 0; $k = 0; for ($i1 = 0; $i1 < $this->size+$this->max_ch && $sw == 0; $i1++) { if ($this->pi_w[$i1] > 1) { if ($x <= $this->ro[$i1]) { $sw = 1; $k = $i1; } } } return $k; } /********************/ /* 標準的な初期設定 */ /********************/ function Init_std() { /* 初期設定 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($i1 < $this->size) $this->pi_w[$i1] = 1; // 適応度の計算前 else $this->pi_w[$i1] = 0; // 未使用 } /* 遺伝子の決定 */ for ($i1 = 0; $i1 < $this->size; $i1++) { $sw1 = 0; while ($sw1 == 0) { // 遺伝子長の決定 if ($this->min_len < 0) $length = $this->max_len; else { $length = intval(uniform() * ($this->max_len - $this->min_len + 1) + $this->min_len); if ($length > $this->max_len) $length = $this->max_len; } $this->len[$i1] = $length; // 遺伝子の決定 for ($i2 = 0; $i2 < $length; $i2++) { $sw2 = 0; while ($sw2 == 0) { $lid = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l); if ($lid > $this->allele_u) $lid = $this->allele_u; $this->ind[$i1][$i2] = $lid; // 重複遺伝子のチェック $sw2 = 1; if ($this->dup_a == 0) { for ($i3 = 0; $i3 < $i2 && $sw2 > 0; $i3++) { if ($lid == $this->ind[$i1][$i3]) $sw2 = 0; } } } } // 重複個体のチェック $sw1 = 1; if ($this->dup_s == 0) { for ($i2 = 0; $i2 < $i1 && $sw1 > 0; $i2++) { if ($this->len[$i1] == $this->len[$i2]) { $sw2 = 0; for ($i3 = 0; $i3 < $this->len[$i1] && $sw2 == 0; $i3++) { if ($this->ind[$i1][$i3] != $this->ind[$i2][$i3]) $sw2 = 1; } if ($sw2 == 0) $sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ function Out_std($sw, $out_m, $gen, $name) { $k = 0; if ($sw >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); fscanf(STDIN, "%d", $pr); } else $pr = -1; if ($pr != 0) { // 出力先の決定と評価値の出力 if ($pr > 0) { $out = STDOUT; fgets(STDIN); } else { $x = getdate(); $now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒"; $out = fopen($name, "ab"); fwrite($out, "***世代 ".$gen." 適応度 max ".$this->max." (".$this->max_n.") mean ".$this->mean." 時間 ".$now."\n"); } // 詳細出力 for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if (($this->pi_w[$i1] > 1) && ($out_m == 0 || $out_m == 1 && $i1 == $this->max_n)) { $str = $i1." allele"; for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) $str += " ".$this->ind[$i1][$i2]; $str += " value ".$this->pi[$i1]; fwrite($out, $str."\n"); if ($pr > 0) { $k++; if ($k == $pr) { fgets(STDIN); $k = 0; } } } } if ($pr < 0) fclose($out); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供)(default) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数(default=max_ch/2) */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_copy($method = 2, $pair = 0, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータチェック */ if ($method != 1) $method = 2; if ($pair <= 0) $pair = ($method==2) ? intval($this->max_ch/2) : $this->max_ch; else { if ($method == 2 && 2*$pair > $this->max_ch || $method == 1 && $pair > $this->max_ch) exit("***error 子供が多すぎる (C_copy)\n"); } /* 実行 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // コピー for ($i2 = 0; $i2 < $method; $i2++) { $p = ($i2 == 0) ? $p1 : $p2; $k = $this->Position(-1); $this->len[$k] = $this->len[$p]; $this->pi_w[$k] = 1; for ($i3 = 0; $i3 < $this->len[$k]; $i3++) $this->ind[$k][$i3] = $this->ind[$p][$i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数(default=1) */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉(default) */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_point($kosa, $k_point = 1, $k_vr = 0, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { $mn = 0; /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a == 0) exit("***error 交叉方法が不適当 (C_point)\n"); $abs_p = abs($k_point); if ($abs_p == 0 || $abs_p > $this->max_len-1 || $this->min_len > 0 && $abs_p > $this->min_len-1) exit("***error 交叉点の数が不適当 (C_point)\n"); if ($k_vr > 0 && $this->min_len < 0) exit("***error 遺伝子長は可変でなければならない (C_point)\n"); /* 交叉 */ $num = $k_point; for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 交叉位置の数の決定 if ($k_point < 0) { $num = intval(uniform() * $abs_p + 1); if ($num > $abs_p) $num = $abs_p; } // 交叉位置の決定(点の後ろで交叉) for ($i2 = 0; $i2 < $num; $i2++) { // 親1の交叉位置 $sw = 0; while ($sw == 0) { $sw = 1; $this->kou1[$i2] = intval(uniform() * ($this->len[$p1] - 1)); if ($this->kou1[$i2] > $this->len[$p1]-2) $this->kou1[$i2] = $this->len[$p1] - 2; if ($k_vr == 0 && $this->kou1[$i2] > $this->len[$p2]-2) $this->kou1[$i2] = $this->len[$p2] - 2; for ($i3 = 0; $i3 < $i2 && $sw > 0; $i3++) { if ($this->kou1[$i3] == $this->kou1[$i2]) $sw = 0; } } // 親2の交叉位置 if ($k_vr > 0) { $sw = 0; while ($sw == 0) { $sw = 1; $this->kou2[$i2] = intval(uniform() * ($this->len[$p2] - 1)); if ($this->kou2[$i2] > $this->len[$p2]-2) $this->kou2[$i2] = $this->len[$p2] - 2; for ($i3 = 0; $i3 < $i2 && $sw > 0; $i3++) { if ($this->kou2[$i3] == $this->kou2[$i2]) $sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ $c1 = 0; $c2 = 0; $t11 = 0; $t21 = 0; // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; for ($i2 = 0; $i2 < $num+1; $i2++ ) { // 次の交叉位置を求める if ($i2 == $num) { // 最後 $t12 = $this->len[$p1]; $t22 = $this->len[$p2]; } else { // 親1 $t12 = $this->max_len; for ($i3 = 0; $i3 < $num; $i3++) { if ($this->kou1[$i3] >= 0 && $this->kou1[$i3] <= $t12) { $t12 = $this->kou1[$i3]; $mn = $i3; } } $this->kou1[$mn] = -1; $t12++; // 親2 if ($k_vr == 0) $t22 = $t12; else { $t22 = $this->max_len; for ($i3 = 0; $i3 < $num; $i3++) { if ($this->kou2[$i3] >= 0 && $this->kou2[$i3] <= $t22) { $t22 = $this->kou2[$i3]; $mn = $i3; } } $this->kou2[$mn] = -1; $t22++; } } // 指定箇所のコピー for ($i3 = $t11; $i3 < $t12; $i3++) { if ($i2%2 == 0) { if ($c1 < $this->max_len) { $this->ind[$k1][$c1] = $this->ind[$p1][$i3]; $c1++; } } else { if ($c2 < $this->max_len) { $this->ind[$k2][$c2] = $this->ind[$p1][$i3]; $c2++; } } } for ($i3 = $t21; $i3 < $t22; $i3++) { if ($i2%2 == 0) { if ($c2 < $this->max_len) { $this->ind[$k2][$c2] = $this->ind[$p2][$i3]; $c2++; } } else { if ($c1 < $this->max_len) { $this->ind[$k1][$c1] = $this->ind[$p2][$i3]; $c1++; } } } // 交叉位置の移動 $t11 = $t12; $t21 = $t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_uniform($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a == 0) exit("***error 交叉方法が不適当 (C_uniform)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_uniform)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { if (uniform() > 0.5) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; } else { $this->ind[$k1][$i2] = $this->ind[$p2][$i2]; $this->ind[$k2][$i2] = $this->ind[$p1][$i2]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_mean($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_mean)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $this->max_ch; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(1, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k = $this->Position(-1); $this->len[$k] = $this->len[$p1]; $this->pi_w[$k] = 1; // 交叉 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) $this->ind[$k][$i2] = ($this->ind[$p1][$i2] + $this->ind[$p2][$i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_cycle($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_cycle)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_cycle)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 初期設定 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->kou1[$i2] = 0; $this->kou2[$i2] = 0; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 $sw = 0; while ($sw == 0) { $sw = 1; $p = intval(uniform() * $this->len[$p1]); if ($p >= $this->len[$p1]) $p = $this->len[$p1] - 1; if ($this->kou1[$p] == 0 && $this->kou2[$p] == 0) { $this->kou1[$p] = 1; $this->kou2[$p] = 1; $this->ind[$k1][$p] = $this->ind[$p1][$p]; $this->ind[$k2][$p] = $this->ind[$p2][$p]; for ($i2 = 0; $i2 < $this->len[$p1] && $sw > 0; $i2++) { if ($this->ind[$p2][$p] == $this->ind[$p1][$i2]) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->kou1[$i2] = 1; $sw = 0; } } $sw = 1; for ($i2 = 0; $i2 < $this->len[$p2] && $sw > 0; $i2++) { if ($this->ind[$p1][$p] == $this->ind[$p2][$i2]) { $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; $this->kou2[$i2] = 1; $sw = 0; } } } } $sw = 0; $i2 = 0; $i3 = 0; while ($sw == 0) { while ($sw == 0 && $i2 < $this->len[$p1]) { if ($this->kou1[$i2] == 0) $sw = 1; else $i2++; } $sw = 0; while ($sw == 0 && $i3 < $this->len[$p2]) { if ($this->kou2[$i3] == 0) $sw = 1; else $i3++; } if ($i2 < $this->len[$p1] && $i3 < $this->len[$p2]) { $this->ind[$k1][$i2] = $this->ind[$p2][$i3]; $this->ind[$k2][$i3] = $this->ind[$p1][$i2]; $sw = 0; $i2++; $i3++; } else $sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_part($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_part)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_part)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 $p = intval(uniform() * $this->len[$p1]); if ($p >= $this->len[$p1]) $p = $this->len[$p1] - 1; for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; } for ($i2 = $p; $i2 < $this->len[$p1]; $i2++) { $sw = 0; $lv = $this->ind[$k1][$i2]; for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($this->ind[$k2][$i2] == $this->ind[$k1][$i3]) { $this->ind[$k1][$i2] = $this->ind[$k1][$i3]; $this->ind[$k1][$i3] = $lv; $sw = 1; } } $sw = 0; for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($lv == $this->ind[$k2][$i3]) { $this->ind[$k2][$i3] = $this->ind[$k2][$i2]; $this->ind[$k2][$i2] = $lv; $sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_seq($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_seq)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_seq)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 $p = intval(uniform() * ($this->len[$p1] - 1)); if ($p >= $this->len[$p1]-1) $p = $this->len[$p1] - 2; for ($i2 = 0; $i2 <= $p; $i2++) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; } $pp = 0; for ($i2 = $p+1; $i2 < $this->len[$p1]; $i2++) { $sw = 0; for ($i3 = $pp; $i3 < $this->len[$p2] && $sw == 0; $i3++) { for ($i4 = $p+1; $i4 < $this->len[$p1] && $sw == 0; $i4++) { if ($this->ind[$p2][$i3] == $this->ind[$p1][$i4]) { $sw = 1; $pp = $i3 + 1; $this->ind[$k1][$i2] = $this->ind[$p1][$i4]; } } } } $pp = 0; for ($i2 = $p+1; $i2 < $this->len[$p2]; $i2++) { $sw = 0; for ($i3 = $pp; $i3 < $this->len[$p1] && $sw == 0; $i3++) { for ($i4 = $p+1; $i4 < $this->len[$p2] && $sw == 0; $i4++) { if ($this->ind[$p1][$i3] == $this->ind[$p2][$i4]) { $sw = 1; $pp = $i3 + 1; $this->ind[$k2][$i2] = $this->ind[$p2][$i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_useq($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_useq)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_useq)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->ind[$k1][$i2] = $this->ind[$p1][$i2]; $this->ind[$k2][$i2] = $this->ind[$p2][$i2]; $this->kou1[$i2] = (uniform() < 0.5) ? 0 : 1; } $p = 0; for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { if ($this->kou1[$i2] > 0) { $sw = 0; for ($i3 = $p; $i3 < $this->len[$p2] && $sw == 0; $i3++) { for ($i4 = 0; $i4 < $this->len[$p1] && $sw == 0; $i4++) { if ($this->ind[$p2][$i3] == $this->ind[$p1][$i4] && $this->kou1[$i4] > 0) { $sw = 1; $p = $i3 + 1; $this->ind[$k1][$i2] = $this->ind[$p1][$i4]; } } } } } $p = 0; for ($i2 = 0; $i2 < $this->len[$p2]; $i2++) { if ($this->kou1[$i2] > 0) { $sw = 0; for ($i3 = $p; $i3 < $this->len[$p1] && $sw == 0; $i3++) { for ($i4 = 0; $i4 < $this->len[$p2] && $sw == 0; $i4++) { if ($this->ind[$p1][$i3] == $this->ind[$p2][$i4] && $this->kou1[$i4] > 0) { $sw = 1; $p = $i3 + 1; $this->ind[$k2][$i2] = $this->ind[$p2][$i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_upos($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { /* 初期設定とデータのチェック */ $pair = $this->max_ch / 2; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_upos)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_upos)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p2]; // 交叉 for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $this->kou1[$i2] = (uniform() < 0.5) ? 0 : 1; if ($this->kou1[$i2] > 0) { $this->ind[$k1][$i2] = $this->ind[$p2][$i2]; $this->ind[$k2][$i2] = $this->ind[$p1][$i2]; } } $p = 0; for ($i2 = 0; $i2 < $this->len[$p1]; $i2++) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($this->kou1[$i3] > 0 && $this->ind[$p1][$i2] == $this->ind[$k1][$i3]) $sw = 1; } if ($sw == 0) { for ($i3 = $p; $i3 < $this->len[$p1] && $sw == 0; $i3++) { if ($this->kou1[$i3] == 0) { $this->ind[$k1][$i3] = $this->ind[$p1][$i2]; $p = $i3 + 1; $sw = 1; } } } } $p = 0; for ($i2 = 0; $i2 < $this->len[$p2]; $i2++) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$p2] && $sw == 0; $i3++) { if ($this->kou1[$i3] > 0 && $this->ind[$p2][$i2] == $this->ind[$k2][$i3]) $sw = 1; } if ($sw == 0) { for ($i3 = $p; $i3 < $this->len[$p2] && $sw == 0; $i3++) { if ($this->kou1[$i3] == 0) { $this->ind[$k2][$i3] = $this->ind[$p2][$i2]; $p = $i3 + 1; $sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム(default) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値(default=0) */ /* k_step : β(default=1) */ /*******************************************************************/ function C_edge($kosa, $k_method = -1, $k_bias = 0.0, $k_step = 1.0) { $e = array(2); $k0 = 0; /* 初期設定とデータのチェック */ $pair = $this->max_ch; if ($this->dup_a != 0) exit("***error 交叉方法が不適当 (C_edge)\n"); if ($this->min_len > 0) exit("***error 遺伝子長は固定長でなければならない (C_edge)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $pair; $i1++) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(1, 1); // 交叉する場合 else { // 親の選択 $p1 = $this->Select($k_method, $k_bias, $k_step); $sw = 0; while ($sw == 0) { $p2 = $this->Select($k_method, $k_bias, $k_step); if ($p1 != $p2) $sw = 1; } // 遺伝子長 $k = $this->Position(-1); $this->pi_w[$k] = 1; $this->len[$k] = $this->len[$p1]; // エッジマップの初期化 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { $this->edge[$i2][0] = 0; for ($i3 = 1; $i3 <= 4; $i3++) $this->edge[$i2][$i3] = -1; } // 交叉 // エッジマップの作成 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$k] && $sw == 0; $i3++) { if ($i2 == $this->ind[$p1][$i3]) { $sw = 1; if ($i3 == 0) { $e[0] = $this->ind[$p1][$this->len[$k]-1]; $e[1] = $this->ind[$p1][1]; } else { if ($i3 == $this->len[$k]-1) { $e[0] = $this->ind[$p1][$i3-1]; $e[1] = $this->ind[$p1][0]; } else { $e[0] = $this->ind[$p1][$i3-1]; $e[1] = $this->ind[$p1][$i3+1]; } } for ($i4 = 0; $i4 < 2; $i4++) { $this->edge[$i2][0]++; $this->edge[$i2][$this->edge[$i2][0]] = $e[$i4]; } } } $sw = 0; for ($i3 = 0; $i3 < $this->len[$k] && $sw == 0; $i3++) { if ($i2 == $this->ind[$p2][$i3]) { $sw = 1; if ($i3 == 0) { $e[0] = $this->ind[$p2][$this->len[$k]-1]; $e[1] = $this->ind[$p2][1]; } else { if ($i3 == $this->len[$k]-1) { $e[0] = $this->ind[$p2][$i3-1]; $e[1] = $this->ind[$p2][0]; } else { $e[0] = $this->ind[$p2][$i3-1]; $e[1] = $this->ind[$p2][$i3+1]; } } for ($i4 = 0; $i4 < 2; $i4++) { $sw = 1; for ($i5 = 1; $i5 <= $this->edge[$i2][0] && $sw == 1; $i5++) { if ($this->edge[$i2][$i5] == $e[$i4]) $sw = 2; } if ($sw == 1) { $this->edge[$i2][0]++; $this->edge[$i2][$this->edge[$i2][0]] = $e[$i4]; } } } } } // 交叉の実行 // 出発点の決定 $k1 = $this->ind[$p1][0]; $k2 = $this->ind[$p2][0]; if ($this->edge[$k1][0] == $this->edge[$k2][0]) $kk = (uniform() > 0.5) ? $k2 : $k1; else $kk = ($this->edge[$k1][0] < $this->edge[$k2][0]) ? $k1 : $k2; $this->ind[$k][0] = $kk; $p = 1; while ($p < $this->len[$k]) { // ノードの除去 for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { $sw = 0; if ($this->edge[$i2][0] > 0) { for ($i3 = 1; $i3 <= 4 && $sw == 0; $i3++) { if ($this->edge[$i2][$i3] == $kk) { $sw = 1; $this->edge[$i2][$i3] = -1; $this->edge[$i2][0]--; } } } } // 次の現在ノードの選択 $min = 10; $num = 0; for ($i2 = 1; $i2 <= 4; $i2++) { if ($this->edge[$kk][$i2] >= 0) { $k1 = $this->edge[$kk][$i2]; if ($this->edge[$k1][0] >= 0 && $this->edge[$k1][0] < $min) { $num = 1; $min = $this->edge[$k1][0]; $k0 = $k1; } else { if ($this->edge[$k1][0] == $min) $num++; } } } if ($num > 1) { $k1 = intval(uniform() * $num) + 1; if ($k1 > $num) $k1 = $num; $k2 = 0; $k0 = -1; for ($i2 = 1; $i2 <= 4 && $k0 < 0; $i2++) { if ($this->edge[$kk][$i2] >= 0) { if ($this->edge[$this->edge[$kk][$i2]][0] == $min) { $k2++; if ($k1 == $k2) $k0 = $this->edge[$kk][$i2]; } } } } else { if ($num <= 0) { $num = 0; for ($i2 = 0; $i2 < $this->len[$k]; $i2++) { if ($i2 != $kk && $this->edge[$i2][0] >= 0) $num++; } if ($num <= 0) exit("***error invalid data (C_edge)\n"); else { $k1 = intval(uniform() * $num) + 1; if ($k1 > $num) $k1 = $num; $k2 = 0; $k0 = -1; for ($i2 = 0; $i2 < $this->len[$k] && $k0 < 0; $i2++) { if ($i2 != $kk && $this->edge[$i2][0] >= 0) { $k2++; if ($k1 == $k2) $k0 = $i2; } } } } } $this->edge[$kk][0] = -1; $this->ind[$k][$p] = $k0; $kk = $k0; $p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数(default=10) */ /*************************************************************/ function C_sub($kosa, $count = 10) { $t22 = 0; /* 初期設定とデータのチェック */ if ((4*$count*$this->size*($this->size-1)) > $this->max_ch) exit("***error 子供が多すぎる (C_sub)\n"); /* 交叉 */ for ($i1 = 0; $i1 < $this->size-1; $i1++) { // 親1 $p1 = $this->Position($i1); if ($p1 >= 0) { for ($i2 = $i1; $i2 < $this->size; $i2++) { // 親2 $p2 = $this->Position($i2); if ($p2 >= 0) { // 交叉しない場合 if (uniform() > $kosa) $this->C_copy(2, 1); // 交叉する場合 else { // 交叉回数の制御 for ($i3 = 0; $i3 < $count; $i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 $t11 = intval(uniform() * $this->len[$p1]); if ($t11 > ($this->len[$p1]-1)) $t11 = $this->len[$p1] - 1; $sw = 0; while ($sw == 0) { $t12 = intval(uniform() * $this->len[$p1]); if ($t12 > ($this->len[$p1]-1)) $t12 = $this->len[$p1] - 1; if ($t12 != $t11) $sw = 1; } if ($t11 > $t12) { $k1 = $t11; $t11 = $t12; $t12 = $k1; } // 親2の交叉位置 $sw = 0; $t21 = -1; for ($i4 = 0; $i4 < $this->len[$p2] && $t21 < 0; $i4++) { for ($i5 = $t11; $i5 <= $t12 && $t21 < 0; $i5++) { if ($this->ind[$p2][$i4] == $this->ind[$p1][$i5]) $t21 = $i4; } } if ($t21 >= 0) { $t22 = $t21 + $t12 - $t11; if ($t22 < $this->len[$p2]) { $sw = 1; for ($i4 = $t21+1; $i4 <= $t22 && $sw > 0; $i4++) { $sw = 0; for ($i5 = $t11; $i5 <= $t12 && $sw == 0; $i5++) { if ($this->ind[$p2][$i4] == $this->ind[$p1][$i5]) $sw = 1; } } } } // 交叉の実行 if ($sw > 0) { $k1 = $this->Position(-1); $this->pi_w[$k1] = 1; $this->len[$k1] = $this->len[$p1]; $k2 = $this->Position(-1); $this->pi_w[$k2] = 1; $this->len[$k2] = $this->len[$p1]; $k3 = $this->Position(-1); $this->pi_w[$k3] = 1; $this->len[$k3] = $this->len[$p2]; $k4 = $this->Position(-1); $this->pi_w[$k4] = 1; $this->len[$k4] = $this->len[$p2]; for ($i4 = 0; $i4 < $t11; $i4++) { $this->ind[$k1][$i4] = $this->ind[$p1][$i4]; $this->ind[$k2][$i4] = $this->ind[$p1][$i4]; } for ($i4 = $t11; $i4 <= $t12; $i4++) { $this->ind[$k1][$i4] = $this->ind[$p2][$t21+$i4-$t11]; $this->ind[$k2][$i4] = $this->ind[$p2][$t22-$i4+$t11]; } for ($i4 = $t12+1; $i4 < $this->len[$p1]; $i4++) { $this->ind[$k1][$i4] = $this->ind[$p1][$i4]; $this->ind[$k2][$i4] = $this->ind[$p1][$i4]; } for ($i4 = 0; $i4 < $t21; $i4++) { $this->ind[$k3][$i4] = $this->ind[$p2][$i4]; $this->ind[$k4][$i4] = $this->ind[$p2][$i4]; } for ($i4 = $t21; $i4 <= $t22; $i4++) { $this->ind[$k3][$i4] = $this->ind[$p1][$t11+$i4-$t21]; $this->ind[$k4][$i4] = $this->ind[$p1][$t12-$i4+$t21]; } for ($i4 = $t22+1; $i4 < $this->len[$p2]; $i4++) { $this->ind[$k3][$i4] = $this->ind[$p2][$i4]; $this->ind[$k4][$i4] = $this->ind[$p2][$i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ function M_alle($pr) { /* データのチェックと初期設定 */ if ($this->dup_a == 0) exit("***error 突然変異方法が不適当 (M_alle)\n"); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) { if (uniform() <= $pr) { $lid = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l); if ($lid > $this->allele_u) $lid = $this->allele_u; if ($lid != $this->ind[$i1][$i2]) $this->ind[$i1][$i2] = $lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ function M_move($pr) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 位置の決定 */ // p1 $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; // p2 $sw = 0; while ($sw == 0) { $p2 = intval(uniform() * $this->len[$i1]); if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; if ($p2 != $p1) $sw = 1; } /* 実行 */ if ($p2 > $p1) { $ld = $this->ind[$i1][$p2]; for ($i2 = $p2; $i2 > $p1; $i2--) $this->ind[$i1][$i2] = $this->ind[$i1][$i2-1]; $this->ind[$i1][$p1] = $ld; } else { $ld = $this->ind[$i1][$p2]; for ($i2 = $p2; $i2 < $p1-1; $i2++) $this->ind[$i1][$i2] = $this->ind[$i1][$i2+1]; $this->ind[$i1][$p1-1] = $ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /********************************************************/ function M_inv($pr, $wd = 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 区間の決定 */ if ($wd == 0) { $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; $sw = 0; while ($sw == 0) { $p2 = intval(uniform() * $this->len[$i1]); if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; if ($p2 != $p1) $sw = 1; } if ($p1 > $p2) { $p = $p1; $p1 = $p2; $p2 = $p; } } else { $p1 = $this->len[$i1]; while ($p1 > $this->len[$i1]-2) $p1 = intval(uniform() * $this->len[$i1]); $p2 = $p1 + $wd - 1; if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; } /* 実行 */ $sw = 0; while ($sw == 0) { $lid = $this->ind[$i1][$p1]; $this->ind[$i1][$p1] = $this->ind[$i1][$p2]; $this->ind[$i1][$p2] = $lid; $p1++; $p2--; if ($p1 >= $p2) $sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_scram($pr, $wd = 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 区間の決定 */ if ($wd == 0) { $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; $sw = 0; while ($sw == 0) { $p2 = intval(uniform() * $this->len[$i1]); if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; if ($p2 != $p1) $sw = 1; } if ($p1 > $p2) { $p = $p1; $p1 = $p2; $p2 = $p; } } else { $p1 = $this->len[$i1]; while ($p1 > $this->len[$i1]-2) $p1 = intval(uniform() * $this->len[$i1]); $p2 = $p1 + $wd - 1; if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; } /* 実行 */ for ($i2 = $p1; $i2 <= $p2; $i2++) { $p = intval(uniform() * ($p2 - $p1 + 1) + $p1); if ($p > $p2) $p = $p2; $ld = $this->ind[$i1][$i2]; $this->ind[$i1][$i2] = $this->ind[$i1][$p]; $this->ind[$i1][$p] = $ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_chg($pr, $wd = 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { /* 区間等の決定([p1,p2]と[p3,p4]の入れ替え) */ // p1 $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; // p3 $sw = 0; while ($sw == 0) { $p3 = intval(uniform() * $this->len[$i1]); if ($p3 >= $this->len[$i1]) $p3 = $this->len[$i1] - 1; if ($p3 != $p1) $sw = 1; } // 小さい方をp1,p2にする if ($p1 > $p3) { $p = $p1; $p1 = $p3; $p3 = $p; } // p4, p2 $p4 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p3)) + $p3 : $p1 + $wd - 1; if ($p4 >= $this->len[$i1]) $p4 = $this->len[$i1] - 1; $p2 = $p1 + ($p4 - $p3); // 重複部分のチェック if ($p2 >= $p3) { $p = $p3 - 1; $p3 = $p2 + 1; $p2 = $p; $p4 = $p3 + ($p2 - $p1); } /* 実行 */ $p = $p3; for ($i2 = $p1; $i2 <= $p2; $i2++) { $ld = $this->ind[$i1][$i2]; $this->ind[$i1][$i2] = $this->ind[$i1][$p]; $this->ind[$i1][$p] = $ld; $p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(deafult) */ /**********************************************************************/ function M_dup($pr, $wd = 0) { /* データのチェック */ if ($this->dup_a == 0) exit("***error 突然変異方法が不適当 (M_dup)\n"); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 $p1 = intval(uniform() * $this->len[$i1]); if ($p1 >= $this->len[$i1]) $p1 = $this->len[$i1] - 1; // p3 $sw = 0; while ($sw == 0) { $p3 = intval(uniform() * $this->len[$i1]); if ($p3 >= $this->len[$i1]) $p3 = $this->len[$i1] - 1; if ($p3 != $p1) $sw = 1; } // 区間を決める if ($p3 > $p1) { $p4 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p3)) + $p3 : $p3 + $wd - 1; if ($p4 >= $this->len[$i1]) $p4 = $this->len[$i1] - 1; $p2 = $p1 + ($p4 - $p3); } else { $p2 = ($wd == 0) ? intval(uniform() * ($this->len[$i1] - $p1)) + $p1 :$p1 + $wd - 1; if ($p2 >= $this->len[$i1]) $p2 = $this->len[$i1] - 1; $p4 = $p3 + ($p2 - $p1); } // 実行 $p = $p4; for ($i2 = $p2; $i2 >= $p1; $i2--) { $this->ind[$i1][$p] = $this->ind[$i1][$i2]; $p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布(default) */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限(default=0.0) */ /* s : 標準偏差または一様分布の上限(default=1.0) */ /******************************************************/ function M_per($pr, $method = 0, $m = 0.0, $s = 1.0) { $wd = 0.0; /* データのチェックと初期設定 */ if ($this->dup_a == 0) exit("***error 突然変異方法が不適当 (M_per)\n"); if ($method > 0) $wd = $s - $m; /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) { if (uniform() <= $pr) { if ($method == 0) $w = norm_d($m, $s); else { $w = uniform() * $wd; if (uniform() < 0.5) $w = -$w; } $x1 = (double)$this->ind[$i1][$i2] + $w; if ($x1 > $this->allele_u) $x1 = $this->allele_u; else { if ($x1 < $this->allele_l) $x1 = $this->allele_l; } $this->ind[$i1][$i2] = intval($x1); } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_ins($pr, $wd = 0) { /* データのチェック */ if ($this->dup_a == 0 || $this->min_len < 0) exit("***error 突然変異方法が不適当 (M_ins)\n"); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { // 挿入位置の決定 $p = intval(uniform() * ($this->len[$i1]+1)); if ($p > $this->len[$i1]) $p = $this->len[$i1]; // 挿入する遺伝子長の決定 $l = ($wd == 0) ? intval(uniform() * ($this->max_len - $this->len[$i1] + 1)) : $wd; if ($l > $this->max_len-$this->len[$i1]) $l = $this->max_len - $this->len[$i1]; else { if ($l <= 0) $l = 1; } // 実行 // 挿入場所の確保 if ($p < $this->len[$i1]) { for ($i2 = $this->len[$i1]+$l-1; $i2 >= $p; $i2--) $this->ind[$i1][$i2] = $this->ind[$i1][$i2-$l]; } // 挿入場所の遺伝子の決定 for ($i2 = $p; $i2 < $p+$l; $i2++) { $ld = intval(uniform() * ($this->allele_u - $this->allele_l + 1) + $this->allele_l); if ($ld > $this->allele_u) $ld = $this->allele_u; $this->ind[$i1][$i2] = $ld; } $this->len[$i1] += $l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム(default) */ /**********************************************************************/ function M_del($pr, $wd = 0) { /* データのチェック */ if ($this->dup_a == 0 || $this->min_len < 0) exit("***error 突然変異方法が不適当 (M_del)\n"); exit(1); /* 実行 */ for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1 && uniform() <= $pr) { // 削除位置の決定 $p = intval(uniform() * $this->len[$i1]); if ($p >= $this->len[$i1]) $p = $this->len[$i1] - 1; // 削除する遺伝子長の決定 $max = ($this->len[$i1]-$this->min_len < $this->len[$i1]-$p) ? $this->len[$i1] - $this->min_len : $this->len[$i1] - $p; $l = ($wd == 0) ? intval(uniform() * $max + 1) : $wd; if ($l > $max) $l = $max; // 実行 for ($i2 = 0; $i2 < $this->len[$i1]-$p-$l; $i2++) $this->ind[$i1][$p+$i2] = $this->ind[$i1][$p+$i2+$l]; $this->len[$i1] -= $l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ function S_roul($elite = 0, $s_method = 1, $s_bias = 0.0, $s_step = 1.0) { $count = 0; $k = 0; $n = 0; /* 値のチェックと初期設定 */ if ($s_method != 0 && $s_method != 2) $s_method = 1; if ($elite > $this->size) exit("***error エリートで残す数が多すぎる (S_roul)\n"); if ($s_method == 2 && $s_step <= 0.0) $s_step = 1.0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) $this->s_w[$i1] = 0; /* 重複個体を削除 */ if ($this->dup_s == 0) { for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 0) { for ($i2 = $i1+1; $i2 < $this->size+$this->max_ch; $i2++) { if ($this->pi_w[$i2] > 0 && $this->len[$i1] == $this->len[$i2]) { $sw = 0; for ($i3 = 0; $i3 < $this->len[$i1] && $sw == 0; $i3++) { if ($this->ind[$i1][$i3] != $this->ind[$i2][$i3]) $sw = 1; } if ($sw == 0) $this->pi_w[$i2] = 0; } } } } } for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1) $n++; } if ($n < 0 || $this->dup_s == 0 && $n < $this->size) exit("***error 残す個体がない (S_roul)\n"); /* 淘汰して残す個体を選ぶ */ // エリートの選択 $sw = 0; while ($k < $elite && $k < $n && $sw == 0) { $max = -1; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] > 1 && $this->s_w[$i1] == 0) { if ($max < 0 || $this->pi[$i1] > $this->pi[$max]) $max = $i1; } } if ($max < 0) $sw = 1; else { $this->s_w[$max] = 1; $k++; } } // ルーレット選択 while ($count < $this->size+$this->max_ch && $k < $this->size) { $p = $this->Select($s_method, $s_bias, $s_step); if ($this->dup_s == 0 && $this->s_w[$p] > 0) $count++; else { $count = 0; $this->s_w[$p]++; $k++; } } // 選択に失敗した場合の処理 if ($this->dup_s == 0 && $k < $this->size) { for ($i1 = 0; $i1 < $this->size+$this->max_ch && $k < $this->size; $i1++) { if ($this->pi_w[$i1] > 1 && $this->s_w[$i1] == 0) { $this->s_w[$i1] = 1; $k++; } } } // 複数回選択されたものの処理 for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->s_w[$i1] == 0) $this->pi_w[$i1] = 0; } for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->s_w[$i1] > 0) { if ($this->s_w[$i1] > 1) { for ($i2 = 2; $i2 <= $this->s_w[$i1]; $i2++) { $k = $this->Position(-1); $this->len[$k] = $this->len[$i1]; $this->pi_w[$k] = 2; $this->pi[$k] = $this->pi[$i1]; for ($i3 = 0; $i3 < $this->len[$i1]; $i3++) $this->ind[$k][$i3] = $this->ind[$i1][$i3]; } } } } } } /***********************************/ /* [0, 1] 区間の一様分布変量の発生 */ /***********************************/ function uniform() { return mt_rand() / mt_getrandmax(); } /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ function norm_d($m, $s) { $x = 0.0; for ($i1 = 0; $i1 < 12; $i1++) $x += uniform(); $x = $s * ($x - 6.0) + $m; return $x; } /************************/ /* クラスFunctionの定義 */ /************************/ class Func extends Species { private $cv; // 2進数を10進数の変換する係数 private $max_gen; // 最大世代交代数 private $kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 多点交叉 // =2 : 一様交叉 // =3 : 平均化交叉 private $kosa; // 交叉確率 private $k_point; // 交差点の数(負の時は,1から-point間のランダム) private $k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) private $k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private $k_bias; // α,または,method=2の場合は初期値 private $k_step; // β private $mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 対立遺伝子への置換 // =1 : 移動 // =2 : 逆位 // =3 : スクランブル // =4 : 転座 // =5 : 重複 // =6 : 摂動 private $mute; // 突然変異率 private $wd; // 突然変異に使用する部分遺伝子長 private $m_mean; // 摂動の平均値 private $m_std; // 摂動の標準偏差 private $elite; // エリート選択で残す数 private $s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 private $s_bias; // α,または,s_method=2の場合は初期値 private $s_step; // β private $out_d; // 表示間隔 private $out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) private $out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 private $o_file; // 出力ファイル名 /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : Func定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ function Func ($name1, $name2, $seed) { parent::Species($name1, $seed); $in = fopen($name2, "rb"); fscanf($in, "%*s %d %*s %d", $this->out_lvl, $this->out_m); fscanf($in, "%*s %s %*s %d", $this->o_file, $this->out_d); fscanf($in, "%*s %d %*s %lf %*s %d %*s %d %*s %d %*s %lf %*s %lf", $this->kosa_m, $this->kosa, $this->k_point, $this->k_vr, $this->k_method, $this->k_bias, $this->k_step); fscanf($in, "%*s %d %*s %lf %*s %d %*s %lf %*s %lf", $this->mute_m, $this->mute, $this->wd, $this->m_mean, $this->m_std); fscanf($in, "%*s %d %*s %d %*s %lf %*s %lf", $this->elite, $this->s_method, $this->s_bias, $this->s_step); fscanf($in, "%*s %d", $this->max_gen); $this->cv = 1.0 / (pow(2.0, $this->max_len) - 1.0); fclose($in); } /**************/ /* 全体の制御 */ /**************/ function Control() { $gen = 1; // 初期集団の発生 $this->Init_std(); // 評価 $this->Adap(); // 出力 printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean); if (abs($this->out_lvl) > 0) $this->Output($gen); // 世代交代 for ($gen = 2; $gen <= $this->max_gen; $gen++) { // 交叉 switch ($this->kosa_m) { case -1: break; case 0: $this->C_copy(); // 親のコピー break; case 1: $this->C_point($this->kosa, $this->k_point); // 多点交叉 break; case 2: $this->C_uniform($this->kosa); // 一様交叉 break; case 3: $this->C_mean($this->kosa); // 平均化交叉 break; default: break; } // 突然変異 switch ($this->mute_m) { case -1: break; case 0: $this->M_alle($this->mute); // 対立遺伝子への置換 break; case 1: $this->M_move($this->mute); // 移動 break; case 2: $this->M_inv($this->mute, $this->wd); // 逆位 break; case 3: $this->M_scram($this->mute, $this->wd); // スクランブル break; case 4: $this->M_chg($this->mute, $this->wd); // 転座 break; case 5: $this->M_dup($this->mute, $this->wd); // 重複 break; case 6: $this->M_per($this->mute, $this->wd, $this->m_mean, $this->m_std); // 摂動 break; default: break; } // 適応度 $this->Adap(); // 淘汰 $this->S_roul($this->elite); // 出力 if ($gen%$this->out_d == 0) printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean); if (abs($this->out_lvl) > 0) { if ($gen%abs($this->out_lvl) == 0) $this->Output($gen); } } $gen--; $k1 = $this->out_m; $this->out_m = 0; printf("***世代 %d 適応度 max %f (%d) mean %f\n", $gen, $this->max, $this->max_n, $this->mean); $this->Output($gen); $this->out_m = $k1; } /****************/ /* 適応度の計算 */ /****************/ function Adap() { $n = 0; $this->max = 0.0; $this->max_n = -1; $this->mean = 0.0; for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if ($this->pi_w[$i1] == 1) { $x = 0.0; $y = 0.0; for ($i2 = $this->len[$i1]-1; $i2 >= 0; $i2--) { if ($this->ind[$i1][$i2] > 0) $x += pow(2.0, $y); $y += 1.0; } $x *= $this->cv; $this->pi[$i1] = sin(3.0*$x) + 0.5 * sin(9.0*$x) + sin(15.0*$x+50.0); $this->pi_w[$i1] = 2; } if ($this->pi_w[$i1] > 0) { $this->mean += $this->pi[$i1]; $n++; if ($this->max_n < 0 || $this->pi[$i1] > $this->max) { $this->max = $this->pi[$i1]; $this->max_n = $i1; } } } $this->mean /= $n; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ function Output($gen) { $k = 0; if ($this->out_lvl >= 0) { printf(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); fscanf(STDIN, "%d", $pr); } else $pr = -1; if ($pr != 0) { // 出力先の決定と評価値の出力 if ($pr > 0) { $out = STDOUT; fgets(STDIN); } else { $x = getdate(); $now = $x["hours"]."時".$x["minutes"]."分".$x["seconds"]."秒"; $out = fopen($this->o_file, "ab"); fwrite($out, "***世代 ".$gen." 適応度 max ".$this->max." (".$this->max_n.") mean ".$this->mean." 時間 ".$now."\n"); } // 詳細出力 for ($i1 = 0; $i1 < $this->size+$this->max_ch; $i1++) { if (($this->pi_w[$i1] > 1) && ($this->out_m ==0 || $this->out_m == 1 && $i1 == $this->max_n)) { fprintf($out, "%d allele", $i1); for ($i2 = 0; $i2 < $this->len[$i1]; $i2++) fprintf($out, " %d", $this->ind[$i1][$i2]); $x = 0.0; $y = 0.0; for ($i2 = $this->len[$i1]-1; $i2 >= 0; $i2--) { if ($this->ind[$i1][$i2] > 0) $x += pow(2.0, $y); $y += 1.0; } $x *= $this->cv; fprintf($out, " x %f y %f\n", $x, $this->pi[$i1]); if ($pr > 0) { $k++; if ($k == $pr) { fgets(STDIN); $k = 0; } } } } if ($pr < 0) fclose($out); } } } /****************/ /* main program */ /****************/ // 入力ミス if (count($argv) <= 1) exit("***error ファイル名を入力して下さい\n"); // 入力OK else { // ファイルのオープン $in = fopen($argv[1], "rb"); if ($in == NULL) exit("***error ファイル名が不適当です\n"); // 入力データファイル名の入力 fscanf($in, "%d", $n); // データの数 $seed = array($n); $i_file1 = array($n); $i_file2 = array($n); for ($i1 = 0; $i1 < $n; $i1++) { $seed[$i1] = 1000 * $i1 + 1234567; fscanf($in, "%s %s", $i_file1[$i1], $i_file2[$i1]); } fclose($in); // 実行(乱数の初期値を変える) for ($i1 = 0; $i1 < $n; $i1++) { printf("\n+++++ケース %d+++++\n", $i1+1); $fn = new Func ($i_file1[$i1], $i_file2[$i1], $seed[$i1]); $fn->Control(); } } //------------------ケーススタディデータ(data_cf.txt)------ /* 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt */ //------------------Species記述データ(data1_f.txt)--------- /* 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 */ //------------------Func記述データ(data2_f.txt)-------- /* 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 */ ?>
#################################### # 遺伝的アルゴリズムによるTSPの解 # coded by Y.Suganuma #################################### ###################### # クラスSpeciesの定義 ###################### class Species ######################### # コンストラクタ # name : ファイル名 ######################### def initialize(name) # データの入力 inn = open(name, "r") s = inn.gets().split(" ") @_allele_u = Integer(s[1]) # 対立遺伝子上限 @_allele_l = Integer(s[3]) # 対立遺伝子下限 s = inn.gets().split(" ") @_max_len = Integer(s[1]) # 最大遺伝子長 @_min_len = Integer(s[3]) # 最小遺伝子長(負の時は,最大遺伝子長で固定) s = inn.gets().split(" ") @_dup_a = Integer(s[1]) # 遺伝子の重複 # =0 重複を許さない # =1 重複を許す @_dup_s = Integer(s[3]) # 個体の重複(同じ染色体の個体) # =0 重複を許さない # =1 重複を許す s = inn.gets().split(" ") @_size = Integer(s[1]) # 個体総数 @_max_ch = Integer(s[3]) # 子供の数の最大値 # データのチェック if @_size <= 0 print("***error 個体総数≦0 (Constructor)\n") end if @_max_ch < 0 print("***error 子供の数<0 (Constructor)\n") end if @_max_len <= 0 or @_min_len == 0 print("***error 遺伝子長≦0 (Constructor)\n") end if @_max_len < @_min_len print("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n") end if @_allele_u <= @_allele_l print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n") end kind = @_allele_u - @_allele_l + 1 if @_dup_a == 0 and @_max_len > kind print("***error 遺伝子の重複を防ぐことはできない (Constructor)\n") end # 領域の確保 num = @_size + @_max_ch @_ind = Array.new(num) # 集団(個体の集まり) for i1 in 0 ... num @_ind[i1] = Array.new(@_max_len) end @_edge = Array.new(@_max_len) # エッジ組み替え交叉用ワークエリア for i1 in 0 ... @_max_len @_edge[i1] = Array.new(5) end @_pi = Array.new(@_max_len) # 適応度 for i1 in 0 ... @_max_len @_pi[i1] = Array.new(5) end @_pi = Array.new(num) # 適応度 @_ro = Array.new(num) # ルーレット板 @_len = Array.new(num) # 各個体の遺伝子長 @_kou1 = Array.new(@_max_len) # 交叉・突然変異用作業場所1 @_kou2 = Array.new(@_max_len) # 交叉・突然変異用作業場所2 @_s_w = Array.new(num) # 淘汰用指標(選択された回数) @_pi_w = Array.new(num) # 適応度計算指標 # =0 未使用 # =1 適応度計算前(突然変異はこの個体だけに適用) # =2 適応度計算済み(交叉時に親とみなす) @_max = -999999999 # 最大適応度 @_mean = 0.0 # 平均適応度 @_max_n = -1 # 最大適応度の個体番号 end ################################################## # 場所を探す # n >=0 : n番目の親を捜す # -1 : 空いている場所を探す # return : 親の場所,または,空いている場所 # (存在しないときは負の値) ################################################## def Position(n) k = -1 sw = 0 # 空いている場所を探す if n < 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 0 k = i1 break end end if k < 0 print("***error 空いている場所がない --Position--\n") end # n番目の親(pi_w[i]=2)を捜す else for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 2 k += 1 if k == n sw = 1 k = i1 break end end end end return k end ################################################################### # 個体の選択 # method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # bias : α,または,method=2の場合は初期値(default=0) # step : β(default=1) # return : 個体番号 ################################################################### def Select(method, bias, step) sum = 0.0 # ルーレット板の用意 # ランダム if method == -1 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 n += 1 end end sum = 1.0 / n for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = sum end end # 評価値をそのまま利用 elsif method == 0 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 sum += @_pi[i1] n += 1 end end if sum.abs() > 1.0e-10 sum = 1.0 / sum.abs() for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = @_pi[i1] * sum end end else sum = 1.0 / n for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = sum end end end # 最小値からの差 elsif method == 1 min = -1 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 n += 1 if min < 0 or @_pi[i1] < @_pi[min] min = i1 end end end for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = @_pi[i1] - @_pi[min] if @_ro[i1] < bias @_ro[i1] = bias end sum += @_ro[i1] end end if sum > 1.0e-10 sum = 1.0 / sum for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] *= sum end end else sum = 1.0 / n for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = sum end end end # 線形化 elsif method == 2 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = -1.0 n += 1 else @_ro[i1] = 1.0 end end sw = 0 sum = bias while sw == 0 min = -1 for i1 in 0 ... @_size+@_max_ch if @_ro[i1] < 0.0 and (min < 0 or @_pi[i1] < @_pi[min]) min = i1 end end if min < 0 sw = 1 else @_ro[min] = sum sum += @_step end end sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] *= sum end end end sum = 0.0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 sum += @_ro[i1] @_ro[i1] = sum end end # 選択 x = rand(0) sw = 0 k = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 if x <= @_ro[i1] sw = 1 k = i1 break end end end return k end ################### # 標準的な初期設定 ################### def Init_std() # 初期設定 for i1 in 0 ... @_size+@_max_ch if i1 < @_size @_pi_w[i1] = 1 # 適応度の計算前 else @_pi_w[i1] = 0 # 未使用 end end # 遺伝子の決定 for i1 in 0 ... @_size sw1 = 0 length = 0 while sw1 == 0 # 遺伝子長の決定 if @_min_len < 0 length = @_max_len else length = Integer(rand(0) * (@_max_len - @_min_len + 1) + @_min_len) if length > @_max_len length = @_max_len end end @_len[i1] = length # 遺伝子の決定 for i2 in 0 ... length sw2 = 0 while sw2 == 0 lid = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l) if lid > @_allele_u lid = @_allele_u end @_ind[i1][i2] = lid # 重複遺伝子のチェック sw2 = 1 if @_dup_a == 0 for i3 in 0 ... i2 if lid == @_ind[i1][i3] sw2 = 0 break end end end end end # 重複個体のチェック sw1 = 1 if @_dup_s == 0 for i2 in 0 ... i1 if @_len[i1] == @_len[i2] sw2 = 0 for i3 in 0 ... @_len[i1] if @_ind[i1][i3] != @_ind[i2][i3] sw2 = 1 break end end if sw2 == 0 sw1 = 0 break end end end end end end end #################################################### # 標準的な出力 # sw : 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負はファイル) # out_m : 出力方法 # =0 : すべての個体を出力 # =1 : 最大適応度の個体だけを出力 # gen : 現在の世代番号 # name : 出力ファイル名 #################################################### def Out_std(sw, out_m, gen, name) k = 0 pr = -1 if sw >= 0 print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer($stdin.gets()) end if pr != 0 # 出力先の決定と評価値の出力 if pr > 0 out = $stdout $stdin.gets() else now = String(Time.now) out = open(name, "a") out.print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + " 時間 " + now + "\n") # 詳細出力 end for i1 in 0 ... @_size+@_max_ch if (@_pi_w[i1] > 1) and (out_m == 0 or (out_m == 1 and i1 == @_max_n)) out.print(String(i1) + " allele") for i2 in 0 ... @_len[i1] out.print(" " + String(@_ind[i1][i2])) end out.print(" value " + String(@_pi[i1]) + "\n") if pr > 0 k += 1 if k == pr $stdin.gets() k = 0 end end end end if pr < 0 out.close() end end end ################################################################### # 交叉(親のコピー) # method : =2 有性(2つの親から2つの子供)(default) # =1 1つの親から1つの子供 # pair : method=2 の時は親のペア数(default=max_ch/2) # method=1 の時は親の数(=子供の数) # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_copy(method = 2, pair = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータチェック if method != 1 method = 2 end if pair <= 0 if method == 2 pair = Integer(@_max_ch / 2) else pair = @_max_ch end else if method == 2 and 2*pair > @_max_ch or method == 1 and pair > @_max_ch print("***error 子供が多すぎる (C_copy)\n") end end # 実行 for i1 in 0 ... pair # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # コピー for i2 in 0 ... method p = p2 if i2 == 0 p = p1 end k = Position(-1) @_len[k] = @_len[p] @_pi_w[k] = 1 for i3 in 0 ... @_len[k] @_ind[k][i3] = @_ind[p][i3] end end end end ################################################################### # 交叉(多点交叉) # kosa : 交叉確率 # k_point : 交叉点の数(default=1) # (負の時は,1から-k_point間のランダム) # k_vr : =0 両親とも同じ位置で交叉(default) # =1 両親が異なる位置で交叉(遺伝子長は可変) # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_point(kosa, k_point = 1, k_vr = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) mn = 0 # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a == 0 print("***error 交叉方法が不適当 (C_point)\n") end abs_p = k_point.abs() if abs_p == 0 or abs_p > @_max_len-1 or (@_min_len > 0 and abs_p > @_min_len-1) print("***error 交叉点の数が不適当 (C_point)\n") end if k_vr > 0 and @_min_len < 0 print("***error 遺伝子長は可変でなければならない (C_point)\n") end # 交叉 num = k_point for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 交叉位置の数の決定 if k_point < 0 num = Integer(rand(0) * abs_p + 1) if num > abs_p num = abs_p end end # 交叉位置の決定(点の後ろで交叉) for i2 in 0 ... num # 親1の交叉位置 sw = 0 while sw == 0 sw = 1 @_kou1[i2] = Integer(rand(0) * (@_len[p1] - 1)) if @_kou1[i2] > @_len[p1]-2 @_kou1[i2] = @_len[p1] - 2 end if k_vr == 0 and @_kou1[i2] > @_len[p2]-2 @_kou1[i2] = @_len[p2] - 2 end for i3 in 0 ... i2 if @_kou1[i3] == @_kou1[i2] sw = 0 break end end end # 親2の交叉位置 if k_vr > 0 sw = 0 while sw == 0 sw = 1 @_kou2[i2] = Integer(rand(0) * (@_len[p2] - 1)) if @_kou2[i2] > @_len[p2]-2 @_kou2[i2] = @_len[p2] - 2 end for i3 in 0 ... i2 if @_kou2[i3] == @_kou2[i2] sw = 0 break end end end end end # 交叉の実行 # 親1のt11からt12を子1のc1へコピー # 親2のt21からt22を子2のc2へコピー # 次は, # 親1のt11からt12を子2のc2へコピー # 親2のt21からt22を子1のc1へコピー # ・・・・・ c1 = 0 c2 = 0 t11 = 0 t21 = 0 # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] for i2 in 0 ... num+1 # 次の交叉位置を求める if i2 == num # 最後 t12 = @_len[p1] t22 = @_len[p2] else # 親1 t12 = @_max_len for i3 in 0 ... num if @_kou1[i3] >= 0 and @_kou1[i3] <= t12 t12 = @_kou1[i3] mn = i3 end end @_kou1[mn] = -1 t12 += 1 # 親2 if k_vr == 0 t22 = t12 else t22 = @_max_len for i3 in 0 ... num if @_kou2[i3] >= 0 and @_kou2[i3] <= t22 t22 = @_kou2[i3] mn = i3 end end @_kou2[mn] = -1 t22 += 1 end end # 指定箇所のコピー for i3 in t11 ... t12 if i2%2 == 0 if c1 < @_max_len @_ind[k1][c1] = @_ind[p1][i3] c1 += 1 end else if c2 < @_max_len @_ind[k2][c2] = @_ind[p1][i3] c2 += 1 end end end for i3 in t21 ... t22 if i2%2 == 0 if c2 < @_max_len @_ind[k2][c2] = @_ind[p2][i3] c2 += 1 end else if c1 < @_max_len @_ind[k1][c1] = @_ind[p2][i3] c1 += 1 end end end # 交叉位置の移動 t11 = t12 t21 = t22 end end end end ################################################################### # 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, # 親1,0であれば親2の遺伝子を子1が受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_uniform(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a == 0 print("***error 交叉方法が不適当 (C_uniform)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_uniform)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 for i2 in 0 ... @_len[p1] if rand(0) > 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] end end end end end ################################################################### # 交叉(平均化交叉.2つの親の平均値を受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_mean(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_mean)\n") end # 交叉 for i1 in 0 ... @_max_ch # 交叉しない場合 if rand(0) > kosa C_copy(1, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k = Position(-1) @_len[k] = @_len[p1] @_pi_w[k] = 1 # 交叉 for i2 in 0 ... @_len[k] @_ind[k][i2] = Integer((@_ind[p1][i2] + @_ind[p2][i2]) / 2) end end end end ################################################################### # 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を # そのまま各子供が選択する.その位置にある親2(1)の遺伝 # 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 # ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 # 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り # 返し,残りの遺伝子については,子1(2)は,親2(1)の # 遺伝子をその順番通りに受け継ぐ) # 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 # * → → # 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_cycle(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_cycle)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_cycle)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 初期設定 for i2 in 0 ... @_len[p1] @_kou1[i2] = 0 @_kou2[i2] = 0 end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 sw = 0 while sw == 0 sw = 1 p = Integer(rand(0) * @_len[p1]) if p >= @_len[p1] p = @_len[p1] - 1 end if @_kou1[p] == 0 and @_kou2[p] == 0 @_kou1[p] = 1 @_kou2[p] = 1 @_ind[k1][p] = @_ind[p1][p] @_ind[k2][p] = @_ind[p2][p] for i2 in 0 ... @_len[p1] if @_ind[p2][p] == @_ind[p1][i2] @_ind[k1][i2] = @_ind[p1][i2] @_kou1[i2] = 1 sw = 0 break end end sw = 1 for i2 in 0 ... @_len[p2] if @_ind[p1][p] == @_ind[p2][i2] @_ind[k2][i2] = @_ind[p2][i2] @_kou2[i2] = 1 sw = 0 break end end end end sw = 0 i2 = 0 i3 = 0 while sw == 0 while sw == 0 and i2 < @_len[p1] if @_kou1[i2] == 0 sw = 1 else i2 += 1 end end sw = 0 while sw == 0 and i3 < @_len[p2] if @_kou2[i3] == 0 sw = 1 else i3 += 1 end end if i2 < @_len[p1] and i3 < @_len[p2] @_ind[k1][i2] = @_ind[p2][i3] @_ind[k2][i3] = @_ind[p1][i2] sw = 0 i2 += 1 i3 += 1 else sw = 1 end end end end end ################################################################### # 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と # 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ # の2つの遺伝子の位置を交換する.この操作を,選択した点よ # り右にあるすべての遺伝子に対して実施する # 2 4 1 3 6 5 2 4 5 3 6 1 # * → → ・・・・・ # 3 2 5 4 1 6 3 2 1 4 5 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) #******************************************************************/ def C_part(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_part)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_part)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 p = Integer(rand(0) * @_len[p1]) if p >= @_len[p1] p = @_len[p1] - 1 end for i2 in 0 ... @_len[p1] @_ind[k1][i2] = @_ind[p1][i2] @_ind[k2][i2] = @_ind[p2][i2] end for i2 in p ... @_len[p1] sw = 0 lv = @_ind[k1][i2] for i3 in 0 ... @_len[p1] if @_ind[k2][i2] == @_ind[k1][i3] @_ind[k1][i2] = @_ind[k1][i3] @_ind[k1][i3] = lv sw = 1 break end end sw = 0 for i3 in 0 ... @_len[p1] if lv == @_ind[k2][i3] @_ind[k2][i3] = @_ind[k2][i2] @_ind[k2][i2] = lv sw = 1 break end end end end end end ################################################################### # 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の # 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 # の遺伝子を親2の遺伝子の出現順序に並べ替える. # 2 4 1 3 6 5 2 4 1 3 5 6 # * → # 3 2 5 4 1 6 3 2 5 4 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_seq(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_seq)") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_seq)") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 p = Integer(rand(0) * (@_len[p1] - 1)) if p >= @_len[p1]-1 p = @_len[p1] - 2 end for i2 in 0 ... p+1 @_ind[k1][i2] = @_ind[p1][i2] @_ind[k2][i2] = @_ind[p2][i2] end pp = 0 for i2 in p+1 ... @_len[p1] sw = 0 i3 = pp while i3 < @_len[p2] and sw == 0 i4 = p + 1 while i4 < @_len[p1] and sw == 0 if @_ind[p2][i3] == @_ind[p1][i4] sw = 1 pp = i3 + 1 @_ind[k1][i2] = @_ind[p1][i4] end i4 += 1 end i3 += 1 end end pp = 0 for i2 in p+1 ... @_len[p2] sw = 0 i3 = pp while i3 < @_len[p1] and sw == 0 i4 = p + 1 while i4 < @_len[p2] and sw == 0 if @_ind[p1][i3] == @_ind[p2][i4] sw = 1 pp = i3 + 1 @_ind[k2][i2] = @_ind[p2][i4] end i4 += 1 end i3 += 1 end end end end end ################################################################### # 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の順序に従って,他の親の遺伝子 # を並べ替える # 2 4 1 3 6 5 2 4 1 3 6 5 # * * → # 3 2 5 4 1 6 4 2 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_useq(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair =Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_useq)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_useq)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 for i2 in 0 ... @_len[p1] @_ind[k1][i2] = @_ind[p1][i2] @_ind[k2][i2] = @_ind[p2][i2] if rand(0) < 0.5 @_kou1[i2] = 0 else @_kou1[i2] = 1 end end p = 0 for i2 in 0 ... @_len[p1] if @_kou1[i2] > 0 sw = 0 i3 = p while i3 < @_len[p2] and sw == 0 i4 = 0 while i4 < @_len[p1] and sw == 0 if @_ind[p2][i3] == @_ind[p1][i4] and @_kou1[i4] > 0 sw = 1 p = i3 + 1 @_ind[k1][i2] = @_ind[p1][i4] end i4 += 1 end i3 += 1 end end end p = 0 for i2 in 0 ... @_len[p3] if @_kou1[i2] > 0 sw = 0 i3 = p while i3 < @_len[p1] and sw == 0 i4 = 0 while i4 < @_len[p2] and sw == 0 if @_ind[p1][i3] == @_ind[p2][i4] and @_kou1[i4] > 0 sw = 1 p = i3 + 1 @_ind[k2][i2] = @_ind[p2][i4] end i4 += 1 end i3 += 1 end end end end end end ################################################################### # 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の位置に,他の親の同じ遺伝子を # 配置する.残りの遺伝子は,親と同じ順序に配置する. # 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 # * * → → # 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_upos(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_upos)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_upos)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 for i2 in 0 ... @_len[p1] @_kou1[i2] = 1 if rand(0) < 0.5 @_kou1[i2] = 1 end if @_kou1[i2] > 0 @_ind[k1][i2] = @_ind[p2][i2] @_ind[k2][i2] = @_ind[p1][i2] end end p = 0 for i2 in 0 ... @_len[p1] sw = 0 for i3 in 0 ... @_len[p1] if @_kou1[i3] > 0 and @_ind[p1][i2] == @_ind[k1][i3] sw = 1 break end end if sw == 0 for i3 in p ... @_len[p1] if @_kou1[i3] == 0 @_ind[k1][i3] = @_ind[p1][i2] p = i3 + 1 sw = 1 break end end end end p = 0 for i2 in 0 ... @_len[p2] sw = 0 for i3 in 0 ... @_len[p2] if @_kou1[i3] > 0 and @_ind[p2][i2] == @_ind[k2][i3] sw = 1 break end end if sw == 0 for i3 in p ... @_len[p2] if @_kou1[i3] == 0 @_ind[k2][i3] = @_ind[p2][i2] p = i3 + 1 sw = 1 break end end end end end end end ################################################################### # 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は # 0~(max_len-1)である必要がある) # (0) エッジマップを作成する.エッジマップとは,2つの親 # を見て,ノードがどこに接続されているのかを表すもの # であり,例えば,2つの親が, # [A B C D E F] # [B D C A E F] # である場合は, # A B F C E # B A C D F # C B D A # D C E B # E D F A # F A E B # となる. # (1) 両親の2つの出発点の内1つで初期化する.ランダムま # たはステップ(4)の基準に従って選ぶ(現在のノード) # (2) エッジマップから,現在のノードを除く # (3) 現在のノードが接続先のノードを持っていたら,(4)に # 進む.さもなければ,(5)に進む # (4) 現在のノードが持っている接続先ノードの内,最も少な # い接続先ノードを持ったノードを選択し(同じ条件の場 # 合は,ランダム),それを現在のノードとし,(2)に進む # (5) 未接続のノードが残っていればランダムに選択し,(2)に # 戻る.さもなければ,終了する # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_edge(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) e = Array.new(2) k0 = 0 # 初期設定とデータのチェック pair = @_max_ch if @_dup_a != 0 print("***error 交叉方法が不適当 (C_edge)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_edge)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(1, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k = Position(-1) @_pi_w[k] = 1 @_len[k] = @_len[p1] # エッジマップの初期化 for i2 in 0 ... @_len[k] @_edge[i2][0] = 0 for i3 in 1 ... 5 @_edge[i2][i3] = -1 end end # 交叉 # エッジマップの作成 for i2 in 0 ... @_len[k] sw = 0 for i3 in 0 ... @_len[k] if i2 == @_ind[p1][i3] sw = 1 if i3 == 0 e[0] = @_ind[p1][@_len[k]-1] e[1] = @_ind[p1][1] else if i3 == @_len[k]-1 e[0] = @_ind[p1][i3-1] e[1] = @_ind[p1][0] else e[0] = @_ind[p1][i3-1] e[1] = @_ind[p1][i3+1] end end for i4 in 0 ... 2 @_edge[i2][0] += 1 @_edge[i2][@_edge[i2][0]] = e[i4] end break end end sw = 0 for i3 in 0 ... @_len[k] if i2 == @_ind[p2][i3] sw = 1 if i3 == 0 e[0] = @_ind[p2][@_len[k]-1] e[1] = @_ind[p2][1] else if i3 == @_len[k]-1 e[0] = @_ind[p2][i3-1] e[1] = @_ind[p2][0] else e[0] = @_ind[p2][i3-1] e[1] = @_ind[p2][i3+1] end end for i4 in 0 ... 2 sw = 1 for i5 in 1 ... @_edge[i2][0]+1 if @_edge[i2][i5] == e[i4] sw = 2 break end end if sw == 1 @_edge[i2][0] += 1 @_edge[i2][@_edge[i2][0]] = e[i4] end end break end end end # 交叉の実行 # 出発点の決定 k1 = @_ind[p1][0] k2 = @_ind[p2][0] if @_edge[k1][0] == @_edge[k2][0] kk = k1 if rand(0) > 0.5 kk = k2 end else kk = k2 if @_edge[k1][0] < @_edge[k2][0] kk = k2 end end @_ind[k][0] = kk p = 1 while p < @_len[k] # ノードの除去 for i2 in 0 ... @_len[k] sw = 0 if @_edge[i2][0] > 0 for i3 in 1 ... 5 if @_edge[i2][i3] == kk sw = 1 @_edge[i2][i3] = -1 @_edge[i2][0] -= 1 break end end end end # 次の現在ノードの選択 min = 10 num = 0 for i2 in 1 ... 5 if @_edge[kk][i2] >= 0 k1 = @_edge[kk][i2] if @_edge[k1][0] >= 0 and @_edge[k1][0] < min num = 1 min = @_edge[k1][0] k0 = k1 else if @_edge[k1][0] == min num += 1 end end end end if num > 1 k1 = Integer(rand(0) * num) + 1 if k1 > num k1 = num end k2 = 0 k0 = -1 i2 = 1 while i2 <= 4 and k0 < 0 if @_edge[kk][i2] >= 0 if @_edge[@_edge[kk][i2]][0] == min k2 += 1 if k1 == k2 k0 = @_edge[kk][i2] end end end i2 += 1 end else if num <= 0 num = 0 for i2 in 0 ... @_len[k] if i2 != kk and @_edge[i2][0] >= 0 num += 1 end end if num <= 0 print("***error invalid data (C_edge)\n") else k1 = Integer(rand(0) * num) + 1 if k1 > num k1 = num end k2 = 0 k0 = -1 i2 = 0 while i2 < @_len[k] and k0 < 0 if i2 != kk and @_edge[i2][0] >= 0 k2 += 1 if k1 == k2 k0 = i2 end end i2 += 1 end end end end @_edge[kk][0] = -1 @_ind[k][p] = k0 kk = k0 p += 1 end end end end ############################################################## # 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に # 同じ遺伝子のグループがない限り実行されない.たとえば # ***abcd** # *cdab**** # のような両親の時実行され,以下の4つの子供が生成され # る) # ***cdab** # *abcd**** # ***badc** # *dcba**** # 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 # 供が生成される可能性があるので,子供の数としてこの値 # 以上のデータを入力しておく必要がある. # kosa : 交叉確率 # count : 1つのペアーに対する交差回数(default=10) ############################################################## def C_sub(kosa, count = 10) t22 = 0 # 初期設定とデータのチェック if (4*count*@_size*(@_size-1)) > @_max_ch print("***error 子供が多すぎる (C_sub)\n") end # 交叉 for i1 in 0 ... @_size-1 # 親1 p1 = Position(i1) if p1 >= 0 for i2 in i1 ... @_size # 親2 p2 = Position(i2) if p2 >= 0 # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 交叉回数の制御 for i3 in 0 ... count # 交叉位置の決定(点の後ろで交叉) # 親1の交叉位置 t11 = Integer(rand(0) * @_len[p1]) if t11 > (@_len[p1]-1) t11 = @_len[p1] - 1 end sw = 0 while sw == 0 t12 = Integer(rand(0) * @_len[p1]) if t12 > (@_len[p1]-1) t12 = @_len[p1] - 1 end if t12 != t11 sw = 1 end end if t11 > t12 k1 = t11 t11 = t12 t12 = k1 end # 親2の交叉位置 sw = 0 t21 = -1 i4 = 0 while i4 < @_len[p2] and t21 < 0 i5 = t11 while i5 <= t12 and t21 < 0 if @_ind[p2][i4] == @_ind[p1][i5] t21 = i4 end i5 += 1 end i4 += 1 end if t21 >= 0 t22 = t21 + t12 - t11 if t22 < @_len[p2] sw = 1 i4 = t21 + 1 while i4 <= t22 and sw > 0 sw = 0 i5 = t11 while i5 <= t12 and sw == 0 if @_ind[p2][i4] == @_ind[p1][i5] sw = 1 end i5 += 1 end i4 += 1 end end end # 交叉の実行 if sw > 0 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p1] k3 = Position(-1) @_pi_w[k3] = 1 @_len[k3] = @_len[p2] k4 = Position(-1) @_pi_w[k4] = 1 @_len[k4] = @_len[p2] for i4 in 0 ... t11 @_ind[k1][i4] = @_ind[p1][i4] @_ind[k2][i4] = @_ind[p1][i4] end for i4 in t11 ... t12+1 @_ind[k1][i4] = @_ind[p2][t21+i4-t11] @_ind[k2][i4] = @_ind[p2][t22-i4+t11] end for i4 in t12+1 ... @_len[p1] @_ind[k1][i4] = @_ind[p1][i4] @_ind[k2][i4] = @_ind[p1][i4] end for i4 in 0 ... t21 @_ind[k3][i4] = @_ind[p2][i4] @_ind[k4][i4] = @_ind[p2][i4] end for i4 in t21 ... t22+1 @_ind[k3][i4] = @_ind[p1][t11+i4-t21] @_ind[k4][i4] = @_ind[p1][t12-i4+t21] end for i4 in t22+1 ... @_len[p2] @_ind[k3][i4] = @_ind[p2][i4] @_ind[k4][i4] = @_ind[p2][i4] end end end end end end end end end ####################################### # 突然変異(対立遺伝子との置き換え) # pr : 突然変異率 ####################################### def M_alle(pr) # データのチェックと初期設定 if @_dup_a == 0 print("***error 突然変異方法が不適当 (M_alle)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 for i2 in 0 ... @_len[i1] if rand(0) <= pr lid = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l) if lid > @_allele_u lid = @_allele_u end if lid != @_ind[i1][i2] @_ind[i1][i2] = lid end end end end end end ###################################################################### # 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に # 移動する) # pr : 突然変異率 ###################################################################### def M_move(pr) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 位置の決定 # p1 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end # p2 p2 = p1 sw = 0 while sw == 0 p2 = Integer(rand(0) * @_len[i1]) if p2 >= @_len[i1] p2 = @_len[i1] - 1 end if p2 != p1 sw = 1 end end # 実行 if p2 > p1 ld = @_ind[i1][p2] i2 = p2 while i2 > p1 @_ind[i1][i2] = @_ind[i1][i2-1] i2 -= -1 end @_ind[i1][p1] = ld else ld = @_ind[i1][p2] for i2 in p2 ... p1-1 @_ind[i1][i2] = @_ind[i1][i2+1] end @_ind[i1][p1-1] = ld end end end end ######################################################## # 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ######################################################## def M_inv(pr, wd = 0) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間の決定 if wd == 0 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end sw = 0 p2 = p1 while sw == 0 p2 = Integer(rand(0) * @_len[i1]) if p2 >= @_len[i1] p2 = @_len[i1] - 1 end if p2 != p1 sw = 1 end end if p1 > p2 p = p1 p1 = p2 p2 = p end else p1 = @_len[i1] while p1 > @_len[i1]-2 p1 = Integer(rand(0) * @_len[i1]) end p2 = p1 + wd - 1 if p2 >= @_len[i1] p2 = @_len[i1] - 1 end end # 実行 sw = 0 while sw == 0 lid = @_ind[i1][p1] @_ind[i1][p1] = @_ind[i1][p2] @_ind[i1][p2] = lid p1 += 1 p2 -= 1 if p1 >= p2 sw = 1 end end end end end ###################################################################### # 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_scram(pr, wd = 0) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間の決定 if wd == 0 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end sw = 0 p2 = p1 while sw == 0 p2 = Integer(rand(0) * @_len[i1]) if p2 >= @_len[i1] p2 = @_len[i1] - 1 end if p2 != p1 sw = 1 end end if p1 > p2 p = p1 p1 = p2 p2 = p end else p1 = @_len[i1] while p1 > @_len[i1]-2 p1 = Integer(rand(0) * @_len[i1]) end p2 = p1 + wd - 1 if p2 >= @_len[i1] p2 = @_len[i1] - 1 end end # 実行 for i2 in p1 ... p2+1 p = Integer(rand(0) * (p2 - p1 + 1) + p1) if p > p2 p = p2 end ld = @_ind[i1][i2] @_ind[i1][i2] = @_ind[i1][p] @_ind[i1][p] = ld end end end end ###################################################################### # 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし # 重複部分はそのままとする) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_chg(pr, wd = 0) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間等の決定([p1,p2]と[p3,p4]の入れ替え) # p1 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end # p3 sw = 0 p3 = p1 while sw == 0 p3 = Integer(rand(0) * @_len[i1]) if p3 >= @_len[i1] p3 = @_len[i1] - 1 end if p3 != p1 sw = 1 end end # 小さい方をp1,p2にする if p1 > p3 p = p1 p1 = p3 p3 = p end # p4, p2 p4 = p1 + wd - 1 if wd == 0 p4 = Integer(rand(0) * (@_len[i1] - p3)) + p3 end if p4 >= @_len[i1] p4 = @_len[i1] - 1 end p2 = p1 + (p4 - p3) # 重複部分のチェック if p2 >= p3 p = p3 - 1 p3 = p2 + 1 p2 = p p4 = p3 + (p2 - p1) end # 実行 p = p3 for i2 in p1 ... p2+1 ld = @_ind[i1][i2] @_ind[i1][i2] = @_ind[i1][p] @_ind[i1][p] = ld p += 1 end end end end ###################################################################### # 突然変異(重複.2点間の遺伝子を他の位置にコピーする # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(deafult) ###################################################################### def M_dup(pr, wd = 0) # データのチェック if @_dup_a == 0 print("***error 突然変異方法が不適当 (M_dup)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間の決定([p1,p2]を[p3,p4]にコピー) # p1 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end # p3 sw = 0 p3 = p1 while sw == 0 p3 = Integer(rand(0) * @_len[i1]) if p3 >= @_len[i1] p3 = @_len[i1] - 1 end if p3 != p1 sw = 1 end end # 区間を決める p2 = p1 p4 = p1 if p3 > p1 p4 = p3 + wd - 1 if wd == 0 p4 = Integer(rand(0) * (@_len[i1] - p3)) + p3 end if p4 >= @_len[i1] p4 = @_len[i1] - 1 end p2 = p1 + (p4 - p3) else p2 = p1 + wd - 1 if wd == 0 p2 = Integer(rand(0) * (@_len[i1] - p1)) + p1 end if p2 >= @_len[i1] p2 = @_len[i1] - 1 end p4 = p3 + (p2 - p1) # 実行 end p = p4 i2 = p2 while i2 > p1-1 @_ind[i1][p] = @_ind[i1][i2] p -= 1 i2 -= 1 end end end end ###################################################### # 突然変異(摂動.値をある量だけ変化させる) # pr : 突然変異率 # method : =0 正規分布(default) # =1 一様分布 # m : 平均または一様分布の下限(default=0.0) # s : 標準偏差または一様分布の上限(default=1.0) ###################################################### def M_per(pr, method = 0, m = 0.0, s = 1.0) wd = 0.0 # データのチェックと初期設定 if @_dup_a == 0 print("***error 突然変異方法が不適当 (M_per)\n") end if method > 0 wd = s - m end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 for i2 in 0 ... @_len[i1] if rand(0) <= pr if method == 0 w = normalvariate(m, s) else w = rand(0) * wd if rand(0) < 0.5 w = -w end end x1 = float(@_ind[i1][i2]) + w if x1 > @_allele_u x1 = @_allele_u else if x1 < @_allele_l x1 = @_allele_l end end @_ind[i1][i2] = Integer(x1) end end end end end ############################################## # 突然変異(挿入.ある長さの遺伝子を挿入する) # pr : 突然変異率 # wd : >0 幅を固定 # =0 幅をランダム(default) ############################################## def M_ins(pr, wd = 0) # データのチェック if @_dup_a == 0 or @_min_len < 0 print("***error 突然変異方法が不適当 (M_ins)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 挿入位置の決定 p = Integer(rand(0) * (@_len[i1] + 1)) if p > @_len[i1] p = @_len[i1] end # 挿入する遺伝子長の決定 l = wd if wd == 0 l = Integer(rand(0) * (@_max_len - @_len[i1] + 1)) end if l > @_max_len-@_len[i1] l = @_max_len - @_len[i1] else if l <= 0 l = 1 end end # 実行 # 挿入場所の確保 if p < @_len[i1] i2 = @_len[i1] + l - 1 while i2 > p-1 @_ind[i1][i2] = @_ind[i1][i2-l] i2 -= 1 end end # 挿入場所の遺伝子の決定 for i2 in p ... p+l ld = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l) if ld > @_allele_u ld = @_allele_u end @_ind[i1][i2] = ld end @_len[i1] += l end end end ############################################## # 突然変異(削除.ある長さの遺伝子を削除する) # pr : 突然変異率 # wd : >0 幅を固定 # =0 幅をランダム(default) ############################################## def M_del(pr, wd = 0) # データのチェック if @_dup_a == 0 or @_min_len < 0 print("***error 突然変異方法が不適当 (M_del)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 削除位置の決定 p = Integer(rand(0) * @_len[i1]) if p >= @_len[i1] p = @_len[i1] - 1 end # 削除する遺伝子長の決定 max = @_len[i1] - p if @_len[i1]-@_min_len < @_len[i1]-p max = @_len[i1] - @_min_len end l = wd if wd == 0 l = Integer(rand(0) * max + 1) end if l > max l = max end # 実行 for i2 in 0 ... @_len[i1]-p-l @_ind[i1][p+i2] = @_ind[i1][p+i2+l] end @_len[i1] -= l end end end ###################################################################### # 淘汰(エリート・ルーレット選択) # elite : エリートで残す個体数(default=0) # s_method : ルーレット板の作成方法(default=1) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # s_bias : α,または,method=2の場合は初期値(default=0) # s_step : β(default=1) ###################################################################### def S_roul(elite = 0, s_method = 1, s_bias = 0.0, s_step = 1.0) count = 0 k = 0 n = 0 # 値のチェックと初期設定 if s_method != 0 and s_method != 2 s_method = 1 end if elite > @_size print("***error エリートで残す数が多すぎる (S_roul)\n") end if s_method == 2 and s_step <= 0.0 s_step = 1.0 end for i1 in 0 ... @_size+@_max_ch @_s_w[i1] = 0 end # 重複個体を削除 if @_dup_s == 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 0 for i2 in i1+1 ... @_size+@_max_ch if @_pi_w[i2] > 0 and @_len[i1] == @_len[i2] sw = 0 for i3 in 0 ... @_len[i1] if @_ind[i1][i3] != @_ind[i2][i3] sw = 1 break end end if sw == 0 @_pi_w[i2] = 0 end end end end end end for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 n += 1 end end if n < 0 or @_dup_s == 0 and n < @_size print("***error 残す個体がない (S_roul)\n") end # 淘汰して残す個体を選ぶ # エリートの選択 sw = 0 while k < elite and k < n and sw == 0 max = -1 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 and @_s_w[i1] == 0 if max < 0 or @_pi[i1] > @_pi[max] max = i1 end end end if max < 0 sw = 1 else @_s_w[max] = 1 k += 1 end end # ルーレット選択 while count < @_size+@_max_ch and k < @_size p = Select(s_method, s_bias, s_step) if @_dup_s == 0 and @_s_w[p] > 0 count += 1 else count = 0 @_s_w[p] += 1 k += 1 end end # 選択に失敗した場合の処理 if @_dup_s == 0 and k < @_size i1 = 0 while i1 < @_size+@_max_ch and k < @_size if @_pi_w[i1] > 1 and @_s_w[i1] == 0 @_s_w[i1] = 1 k += 1 end i1 += 1 end end # 複数回選択されたものの処理 for i1 in 0 ... @_size+@_max_ch if @_s_w[i1] == 0 @_pi_w[i1] = 0 end end for i1 in 0 ... @_size+@_max_ch if @_s_w[i1] > 0 if @_s_w[i1] > 1 for i2 in 2 ... @_s_w[i1]+1 k = Position(-1) @_len[k] = @_len[i1] @_pi_w[k] = 2 @_pi[k] = @_pi[i1] for i3 in 0 ... @_len[i1] @_ind[k][i3] = @_ind[i1][i3] end end end end end end end #################### # クラスTSPの定義 #################### class TSP < Species ###################################### # コンストラクタ # name1 : Species定義ファイル名 # name2 : TSP定義ファイル名 ###################################### def initialize(name1, name2) super(name1) # 親のコンストラクタ # 基本データの入力 inn = open(name2, "r") s = inn.gets().split(" ") @_out_lvl = Integer(s[1]) # 出力レベル # =0 最終出力だけ # n>0 n世代毎に出力(負の時はファイル) @_out_m = Integer(s[3]) # 出力方法 # =0 すべてを出力 # =1 最大適応度の個体だけを出力 s = inn.gets().split(" ") @_o_file = s[1] # 出力ファイル名 @_out_d = Integer(s[3]) # 表示間隔 s = inn.gets().split(" ") @_kosa_m = Integer(s[1]) # 交叉方法 # =-1 交叉を使用しない # =0 親のコピー # =1 循環交叉 # =2 部分的交叉 # =3 順序交叉 # =4 一様順序交叉 # =5 一様位置交叉 # =6 エッジ組み替え交叉 # =7 サブツアー交叉 @_kosa = Float(s[3]) # 交叉確率 @_k_point = Integer(s[5]) # 交差点の数(負の時は,1から-k_point間のランダム) @_k_vr = Integer(s[7]) # =0 両親とも同じ位置で交叉 # =1 両親が異なる位置で交叉(遺伝子長は可変) @_k_method = Integer(s[9]) # 交叉の時の親の選択方法 # =-1 ランダム # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 @_k_bias = Float(s[11]) # α,または,method=2の場合は初期値 @_k_step = Float(s[13]) # β s = inn.gets().split(" ") @_mute_m = Integer(s[1]) # 突然変異方法 # =-1 突然変異を使用しない # =0 移動 # =1 逆位 # =2 スクランブル # =3 転座 @_mute = Float(s[3]) # 突然変異率 @_wd = Integer(s[5]) # 突然変異に使用する部分遺伝子長 @_m_mean = Float(s[7]) # 摂動の平均値 @_m_std = Float(s[9]) # 摂動の標準偏差 s = inn.gets().split(" ") @_elite = Integer(s[1]) # エリート選択で残す数 @_s_method = Integer(s[3]) # ルーレット板の作成方法 # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 @_s_bias = Float(s[5]) # α,または,s_method=2の場合は初期値 @_s_step = Float(s[7]) # β s = inn.gets().split(" ") @_n_city = Integer(s[1]) # 都市の数 @_max_gen = Integer(s[3]) # 最大世代交代数 s = inn.gets().split(" ") @_kinbo = Integer(s[1]) # 近傍探索(0:行わない,1:行う) @_neib = Integer(s[3]) # 近傍(2 or 3) s = inn.gets().split(" ") @_sel = Integer(s[1]) # エッジの選択方法 # =0 最良のものを選択 # =1 最初のものを選択 if @_kinbo > 0 and @_neib != 2 and @_neib != 3 print("***error 近傍の値が不適当\n") end if @_n_city != @_max_len print("***error 都市数が不適当\n") end # 都市の位置データ @_city = Array.new(@_n_city) for i1 in 0 ... @_n_city @_city[i1] = Array.new(2) s = inn.gets().split(" ") @_city[i1][0] = Integer(s[0]) @_city[i1][1] = Integer(s[1]) end # 距離テーブル @_rg = Array.new(@_n_city) for i1 in 0 ... @_max_len @_rg[i1] = Array.new(@_n_city) end for i1 in 0 ... @_n_city for i2 in i1+1 ... @_n_city x = @_city[i2][0] - @_city[i1][0] y = @_city[i2][1] - @_city[i1][1] @_rg[i1][i2] = Math.sqrt(x * x + y * y).round() end end for i1 in 1 ... @_n_city for i2 in 0 ... i1 @_rg[i1][i2] = @_rg[i2][i1] end end inn.close() end ############### # 全体の制御 ############### def Control() gen = 1 # 初期集団の発生 Init_std() # 評価 if @_kinbo > 0 Kinbo() else Adap() end # 出力 print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n") if @_out_lvl.abs() > 0 Output(gen) end # 世代交代 for gen in 2 ... @_max_gen+1 # 交叉 if @_kosa_m == 0 C_copy() # 親のコピー elsif @_kosa_m == 1 C_cycle(@_kosa) # 循環交叉 elsif @_kosa_m == 2 C_part(@_kosa) # 部分的交叉 elsif @_kosa_m == 3 C_seq(@_kosa) # 順序交叉 elsif @_kosa_m == 4 C_useq(@_kosa) # 一様順序交叉 elsif @_kosa_m == 5 C_upos(@_kosa) # 一様位置交叉 elsif @_kosa_m == 6 C_edge(@_kosa) # エッジ組み替え交叉 elsif @_kosa_m == 7 C_sub(@_kosa, @_k_point) # サブツアー交叉 end # 突然変異 if @_mute_m == 0 M_move(@_mute) # 移動 elsif @_mute_m == 1 M_inv(@_mute) # 逆位 elsif @_mute_m == 2 M_scram(@_mute) # スクランブル elsif @_mute_m == 3 M_chg(@_mute) # 転座 end # 適応度 if @_kinbo > 0 Kinbo() else Adap() end # 淘汰 S_roul(@_elite) # 出力 if gen%@_out_d == 0 print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n") end if @_out_lvl.abs() > 0 if gen%@_out_lvl.abs() == 0 Output(gen) end end end gen -= 1 k1 = @_out_m @_out_m = 0 print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n") Output(gen) @_out_m = k1 end ########################## # 距離の計算 # n_c : 都市の数 # p : 都市番号 # return : 距離(負) ########################## def Kyori(n_c, p) r = 0 n1 = p[0] for i1 in 1 ... n_c n2 = p[i1] r -= @_rg[n1][n2] n1 = n2 end n2 = p[0] r -= @_rg[n1][n2] return r end ################ # 適応度の計算 ################ def Adap() k = 0 @_mean = 0.0 @_max = 0.0 @_max_n = -1 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 @_pi_w[i1] = 2 @_pi[i1] = Kyori(@_len[i1], @_ind[i1]) end if @_pi_w[i1] > 0 k += 1 @_mean += @_pi[i1] if @_max_n < 0 or @_pi[i1] > @_max @_max = @_pi[i1] @_max_n = i1 end end end if k > 0 @_mean /= k end end ###################################### # エッジの入れ替え # n_city : 都市の数 # seq : 訪問する順番 # r_m : 距離の負値 # return : =0 改善がなかった # =1 改善があった ###################################### def Change(n_city, seq, r_m) ch = 0 sw = 0 max = r_m[0] n3 = Integer(rand(0) * (n_city - 2)) if n3 > n_city-3 n3 = n_city - 3 end # 2近傍 i1 = 0 while i1 <= n_city-3 and ch == 0 if n3 == 0 n1 = n_city - 2 else n1 = n_city - 1 end i2 = n3 + 2 while i2 <= n1 and ch == 0 # 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 if i2 == n_city-1 k2 = 0 else k2 = i2 + 1 end # 枝の入れ替え @_kou1[0] = seq[n3] k = 1 i3 = k1 while i3 > n3 @_kou1[k] = seq[i3] k += 1 i3 -= 1 end nn = k2 while nn != n3 @_kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 nn = 0 end end # 評価 r = Kyori(n_city, @_kou1) if r > max max = r sw = 1 for i3 in 0 ... n_city @_kou2[i3] = @_kou1[i3] end if @_sel > 0 ch = 1 end end i2 += 1 end n3 += 1 if n3 > n_city-3 n3 = 0 end i1 += 1 end # 3近傍 if @_neib == 3 and ch == 0 i1 = 0 while i1 <= n_city-3 and ch == 0 n1 = n_city - 2 n2 = n_city - 1 i2 = n3 + 1 while i2 <= n1 and ch == 0 i3 = i2 + 1 while i3 <= n2 and ch == 0 # 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 k2 = k1 if i3 == n_city-1 k2 = 0 else k2 = i3 + 1 end # 枝の入れ替えと評価 # 入れ替え(その1) @_kou1[0] = seq[n3] k = 1 i4 = i2 while i4 > n3 @_kou1[k] = seq[i4] k += 1 i4 -= 1 end i4 = k1 while i4 > i2 @_kou1[k] = seq[i4] k += 1 i4 -= 1 end nn = k2 while nn != n3 @_kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 nn = 0 end end # 評価(その1) r = Kyori(n_city, @_kou1) if r > max max = r sw = 1 for i3 in 0 ... n_city @_kou2[i3] = @_kou1[i3] end if @_sel > 0 ch = 1 end end # 入れ替え(その2) @_kou1[0] = seq[n3] k = 1 i4 = k1 while i4 > i2 @_kou1[k] = seq[i4] k += 1 i4 -= 1 end for i4 in n3+1 ... i2+1 @_kou1[k] = seq[i4] k += 1 end nn = k2 while nn != n3 @_kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 nn = 0 end end # 評価(その2) r = Kyori(n_city, @_kou1) if r > max max = r sw = 1 for i3 in 0 ... n_city @_kou2[i3] = @_kou1[i3] end if @_sel > 0 ch = 1 end end # 入れ替え(その3) @_kou1[0] = seq[n3] k = 1 for i4 in i2+1 ... k1+1 @_kou1[k] = seq[i4] k += 1 end i4 = i2 while i4 > n3 @_kou1[k] = seq[i4] k += 1 i4 -= 1 end nn = k2 while nn != n3 @_kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 nn = 0 end end # 評価(その3) r = Kyori(n_city, @_kou1) if r > max max = r sw = 1 for i3 in 0 ... n_city @_kou2[i3] = @_kou1[i3] end if @_sel > 0 ch = 1 end end # 入れ替え(その4) @_kou1[0] = seq[n3] k = 1 for i4 in i2+1 ... k1+1 @_kou1[k] = seq[i4] k += 1 end for i4 in n3+1 ... i2+1 @_kou1[k] = seq[i4] k += 1 end nn = k2 while nn != n3 @_kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 nn = 0 end end # 評価(その4) r = Kyori(n_city, @_kou1) if r > max max = r sw = 1 for i3 in 0 ... n_city @_kou2[i3] = @_kou1[i3] end if @_sel > 0 ch = 1 end end i3 += 1 end i2 += 1 end n3 += 1 if n3 > n_city-3 n3 = 0 end i1 += 1 end end # 設定 if sw > 0 r_m[0] = max for i1 in 0 ... n_city seq[i1] = @_kou2[i1] end end return sw end ############## # 近傍の探索 ############## def Kinbo() k = 0 @_max = 0.0 @_max_n = -1 @_mean = 0.0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 @_pi_w[i1] = 2 sw = 1 r = Kyori(@_len[i1], @_ind[i1]) while sw > 0 r = Array.new(1) sw = Change(@_len[i1], @_ind[i1], r) end @_pi[i1] = r[0] end if @_pi_w[i1] > 0 k += 1 @_mean += @_pi[i1] if @_max_n < 0 or @_pi[i1] > @_max @_max = @_pi[i1] @_max_n = i1 end end end if k > 0 @_mean /= k end end ############################# # 結果の出力 # gen : 現在の世代番号 ############################# def Output(gen) k = 0 pr = -1 if @_out_lvl >= 0 print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer($stdin.gets()) end if pr != 0 # 出力先の決定と評価値の出力 if pr > 0 out = $stdout $stdin.gets() else now = String(Time.now) out = open(@_o_file, "a") out.print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + " 時間 " + now + "\n") end # 巡回順序の出力 if @_out_m == 0 for i1 in 0 ... @_len[@_max_n] n = @_ind[@_max_n][i1] out.print(String(n) + " " + String(@_city[n][0]) + " " + String(@_city[n][1]) + "\n") if pr > 0 k += 1 if k == pr $stdin.gets() k = 0 end end end end if pr < 0 out.close() end end end end # 入力ミス if ARGV[0] == nil print("***error ファイル名を入力して下さい\n") # 入力OK else # データの数と入力データファイル名の入力 line = gets() n = Integer(line) # データの数 i_file1 = Array.new(n) i_file2 = Array.new(n) for i1 in 0 ... n line = gets() a = line.split(" ") i_file1[i1] = a[0] i_file2[i1] = a[1] end # 実行(乱数の初期値を変える) for i1 in 0 ... n print("\n+++++ケース " + String(i1+1) + "+++++\n") srand(1000 * i1 + 1234567); tsp = TSP.new(i_file1[i1], i_file2[i1]) tsp.Control() end end =begin ----------------ケーススタディデータ(data_ct.txt)------ 3 data1_t.txt data2_t.txt data1_t.txt data2_t.txt data1_t.txt data2_t.txt ---------------Species記述データ(data1_t.txt)--------- 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 ---------------TSP記述データ(data2_t.txt)-------- 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 =end
/********************************************************************/ /* f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 */ /* coded by Y.Suganuma */ /********************************************************************/ ###################### # クラスSpeciesの定義 ###################### class Species ######################### # コンストラクタ # name : ファイル名 ######################### def initialize(name) # データの入力 inn = open(name, "r") s = inn.gets().split(" ") @_allele_u = Integer(s[1]) # 対立遺伝子上限 @_allele_l = Integer(s[3]) # 対立遺伝子下限 s = inn.gets().split(" ") @_max_len = Integer(s[1]) # 最大遺伝子長 @_min_len = Integer(s[3]) # 最小遺伝子長(負の時は,最大遺伝子長で固定) s = inn.gets().split(" ") @_dup_a = Integer(s[1]) # 遺伝子の重複 # =0 重複を許さない # =1 重複を許す @_dup_s = Integer(s[3]) # 個体の重複(同じ染色体の個体) # =0 重複を許さない # =1 重複を許す s = inn.gets().split(" ") @_size = Integer(s[1]) # 個体総数 @_max_ch = Integer(s[3]) # 子供の数の最大値 # データのチェック if @_size <= 0 print("***error 個体総数≦0 (Constructor)\n") end if @_max_ch < 0 print("***error 子供の数<0 (Constructor)\n") end if @_max_len <= 0 or @_min_len == 0 print("***error 遺伝子長≦0 (Constructor)\n") end if @_max_len < @_min_len print("***error 最大遺伝子長<最小遺伝子長 (Constructor)\n") end if @_allele_u <= @_allele_l print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)\n") end kind = @_allele_u - @_allele_l + 1 if @_dup_a == 0 and @_max_len > kind print("***error 遺伝子の重複を防ぐことはできない (Constructor)\n") end # 領域の確保 num = @_size + @_max_ch @_ind = Array.new(num) # 集団(個体の集まり) for i1 in 0 ... num @_ind[i1] = Array.new(@_max_len) end @_edge = Array.new(@_max_len) # エッジ組み替え交叉用ワークエリア for i1 in 0 ... @_max_len @_edge[i1] = Array.new(5) end @_pi = Array.new(@_max_len) # 適応度 for i1 in 0 ... @_max_len @_pi[i1] = Array.new(5) end @_pi = Array.new(num) # 適応度 @_ro = Array.new(num) # ルーレット板 @_len = Array.new(num) # 各個体の遺伝子長 @_kou1 = Array.new(@_max_len) # 交叉・突然変異用作業場所1 @_kou2 = Array.new(@_max_len) # 交叉・突然変異用作業場所2 @_s_w = Array.new(num) # 淘汰用指標(選択された回数) @_pi_w = Array.new(num) # 適応度計算指標 # =0 未使用 # =1 適応度計算前(突然変異はこの個体だけに適用) # =2 適応度計算済み(交叉時に親とみなす) @_max = -999999999 # 最大適応度 @_mean = 0.0 # 平均適応度 @_max_n = -1 # 最大適応度の個体番号 end ################################################## # 場所を探す # n >=0 : n番目の親を捜す # -1 : 空いている場所を探す # return : 親の場所,または,空いている場所 # (存在しないときは負の値) ################################################## def Position(n) k = -1 sw = 0 # 空いている場所を探す if n < 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 0 k = i1 break end end if k < 0 print("***error 空いている場所がない --Position--\n") end # n番目の親(pi_w[i]=2)を捜す else for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 2 k += 1 if k == n sw = 1 k = i1 break end end end end return k end ################################################################### # 個体の選択 # method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # bias : α,または,method=2の場合は初期値(default=0) # step : β(default=1) # return : 個体番号 ################################################################### def Select(method, bias, step) sum = 0.0 # ルーレット板の用意 # ランダム if method == -1 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 n += 1 end end sum = 1.0 / n for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = sum end end # 評価値をそのまま利用 elsif method == 0 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 sum += @_pi[i1] n += 1 end end if sum.abs() > 1.0e-10 sum = 1.0 / sum.abs() for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = @_pi[i1] * sum end end else sum = 1.0 / n for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = sum end end end # 最小値からの差 elsif method == 1 min = -1 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 n += 1 if min < 0 or @_pi[i1] < @_pi[min] min = i1 end end end for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = @_pi[i1] - @_pi[min] if @_ro[i1] < bias @_ro[i1] = bias end sum += @_ro[i1] end end if sum > 1.0e-10 sum = 1.0 / sum for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] *= sum end end else sum = 1.0 / n for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = sum end end end # 線形化 elsif method == 2 n = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] = -1.0 n += 1 else @_ro[i1] = 1.0 end end sw = 0 sum = bias while sw == 0 min = -1 for i1 in 0 ... @_size+@_max_ch if @_ro[i1] < 0.0 and (min < 0 or @_pi[i1] < @_pi[min]) min = i1 end end if min < 0 sw = 1 else @_ro[min] = sum sum += @_step end end sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 @_ro[i1] *= sum end end end sum = 0.0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 sum += @_ro[i1] @_ro[i1] = sum end end # 選択 x = rand(0) sw = 0 k = 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 if x <= @_ro[i1] sw = 1 k = i1 break end end end return k end ################### # 標準的な初期設定 ################### def Init_std() # 初期設定 for i1 in 0 ... @_size+@_max_ch if i1 < @_size @_pi_w[i1] = 1 # 適応度の計算前 else @_pi_w[i1] = 0 # 未使用 end end # 遺伝子の決定 for i1 in 0 ... @_size sw1 = 0 length = 0 while sw1 == 0 # 遺伝子長の決定 if @_min_len < 0 length = @_max_len else length = Integer(rand(0) * (@_max_len - @_min_len + 1) + @_min_len) if length > @_max_len length = @_max_len end end @_len[i1] = length # 遺伝子の決定 for i2 in 0 ... length sw2 = 0 while sw2 == 0 lid = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l) if lid > @_allele_u lid = @_allele_u end @_ind[i1][i2] = lid # 重複遺伝子のチェック sw2 = 1 if @_dup_a == 0 for i3 in 0 ... i2 if lid == @_ind[i1][i3] sw2 = 0 break end end end end end # 重複個体のチェック sw1 = 1 if @_dup_s == 0 for i2 in 0 ... i1 if @_len[i1] == @_len[i2] sw2 = 0 for i3 in 0 ... @_len[i1] if @_ind[i1][i3] != @_ind[i2][i3] sw2 = 1 break end end if sw2 == 0 sw1 = 0 break end end end end end end end #################################################### # 標準的な出力 # sw : 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負はファイル) # out_m : 出力方法 # =0 : すべての個体を出力 # =1 : 最大適応度の個体だけを出力 # gen : 現在の世代番号 # name : 出力ファイル名 #################################################### def Out_std(sw, out_m, gen, name) k = 0 pr = -1 if sw >= 0 print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer($stdin.gets()) end if pr != 0 # 出力先の決定と評価値の出力 if pr > 0 out = $stdout $stdin.gets() else now = String(Time.now) out = open(name, "a") out.print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + " 時間 " + now + "\n") # 詳細出力 end for i1 in 0 ... @_size+@_max_ch if (@_pi_w[i1] > 1) and (out_m == 0 or (out_m == 1 and i1 == @_max_n)) out.print(String(i1) + " allele") for i2 in 0 ... @_len[i1] out.print(" " + String(@_ind[i1][i2])) end out.print(" value " + String(@_pi[i1]) + "\n") if pr > 0 k += 1 if k == pr $stdin.gets() k = 0 end end end end if pr < 0 out.close() end end end ################################################################### # 交叉(親のコピー) # method : =2 有性(2つの親から2つの子供)(default) # =1 1つの親から1つの子供 # pair : method=2 の時は親のペア数(default=max_ch/2) # method=1 の時は親の数(=子供の数) # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_copy(method = 2, pair = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータチェック if method != 1 method = 2 end if pair <= 0 if method == 2 pair = Integer(@_max_ch / 2) else pair = @_max_ch end else if (method == 2 and 2*pair > @_max_ch) or (method == 1 and pair > @_max_ch) print("***error 子供が多すぎる (C_copy)\n") end end # 実行 for i1 in 0 ... pair # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # コピー for i2 in 0 ... method p = p2 if i2 == 0 p = p1 end k = Position(-1) @_len[k] = @_len[p] @_pi_w[k] = 1 for i3 in 0 ... @_len[k] @_ind[k][i3] = @_ind[p][i3] end end end end ################################################################### # 交叉(多点交叉) # kosa : 交叉確率 # k_point : 交叉点の数(default=1) # (負の時は,1から-k_point間のランダム) # k_vr : =0 両親とも同じ位置で交叉(default) # =1 両親が異なる位置で交叉(遺伝子長は可変) # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_point(kosa, k_point = 1, k_vr = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) mn = 0 # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a == 0 print("***error 交叉方法が不適当 (C_point)\n") end abs_p = k_point.abs() if abs_p == 0 or abs_p > @_max_len-1 or (@_min_len > 0 and abs_p > @_min_len-1) print("***error 交叉点の数が不適当 (C_point)\n") end if k_vr > 0 and @_min_len < 0 print("***error 遺伝子長は可変でなければならない (C_point)\n") end # 交叉 num = k_point for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 交叉位置の数の決定 if k_point < 0 num = Integer(rand(0) * abs_p + 1) if num > abs_p num = abs_p end end # 交叉位置の決定(点の後ろで交叉) for i2 in 0 ... num # 親1の交叉位置 sw = 0 while sw == 0 sw = 1 @_kou1[i2] = Integer(rand(0) * (@_len[p1] - 1)) if @_kou1[i2] > @_len[p1]-2 @_kou1[i2] = @_len[p1] - 2 end if k_vr == 0 and @_kou1[i2] > @_len[p2]-2 @_kou1[i2] = @_len[p2] - 2 end for i3 in 0 ... i2 if @_kou1[i3] == @_kou1[i2] sw = 0 break end end end # 親2の交叉位置 if k_vr > 0 sw = 0 while sw == 0 sw = 1 @_kou2[i2] = Integer(rand(0) * (@_len[p2] - 1)) if @_kou2[i2] > @_len[p2]-2 @_kou2[i2] = @_len[p2] - 2 end for i3 in 0 ... i2 if @_kou2[i3] == @_kou2[i2] sw = 0 break end end end end end # 交叉の実行 # 親1のt11からt12を子1のc1へコピー # 親2のt21からt22を子2のc2へコピー # 次は, # 親1のt11からt12を子2のc2へコピー # 親2のt21からt22を子1のc1へコピー # ・・・・・ c1 = 0 c2 = 0 t11 = 0 t21 = 0 # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] for i2 in 0 ... num+1 # 次の交叉位置を求める if i2 == num # 最後 t12 = @_len[p1] t22 = @_len[p2] else # 親1 t12 = @_max_len for i3 in 0 ... num if @_kou1[i3] >= 0 and @_kou1[i3] <= t12 t12 = @_kou1[i3] mn = i3 end end @_kou1[mn] = -1 t12 += 1 # 親2 if k_vr == 0 t22 = t12 else t22 = @_max_len for i3 in 0 ... num if @_kou2[i3] >= 0 and @_kou2[i3] <= t22 t22 = @_kou2[i3] mn = i3 end end @_kou2[mn] = -1 t22 += 1 end end # 指定箇所のコピー for i3 in t11 ... t12 if i2%2 == 0 if c1 < @_max_len @_ind[k1][c1] = @_ind[p1][i3] c1 += 1 end else if c2 < @_max_len @_ind[k2][c2] = @_ind[p1][i3] c2 += 1 end end end for i3 in t21 ... t22 if i2%2 == 0 if c2 < @_max_len @_ind[k2][c2] = @_ind[p2][i3] c2 += 1 end else if c1 < @_max_len @_ind[k1][c1] = @_ind[p2][i3] c1 += 1 end end end # 交叉位置の移動 t11 = t12 t21 = t22 end end end end ################################################################### # 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, # 親1,0であれば親2の遺伝子を子1が受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_uniform(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a == 0 print("***error 交叉方法が不適当 (C_uniform)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_uniform)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 for i2 in 0 ... @_len[p1] if rand(0) > 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] end end end end end ################################################################### # 交叉(平均化交叉.2つの親の平均値を受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_mean(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_mean)\n") end # 交叉 for i1 in 0 ... @_max_ch # 交叉しない場合 if rand(0) > kosa C_copy(1, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k = Position(-1) @_len[k] = @_len[p1] @_pi_w[k] = 1 # 交叉 for i2 in 0 ... @_len[k] @_ind[k][i2] = Integer((@_ind[p1][i2] + @_ind[p2][i2]) / 2) end end end end ################################################################### # 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を # そのまま各子供が選択する.その位置にある親2(1)の遺伝 # 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 # ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 # 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り # 返し,残りの遺伝子については,子1(2)は,親2(1)の # 遺伝子をその順番通りに受け継ぐ) # 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 # * → → # 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_cycle(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_cycle)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_cycle)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 初期設定 for i2 in 0 ... @_len[p1] @_kou1[i2] = 0 @_kou2[i2] = 0 end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 sw = 0 while sw == 0 sw = 1 p = Integer(rand(0) * @_len[p1]) if p >= @_len[p1] p = @_len[p1] - 1 end if @_kou1[p] == 0 and @_kou2[p] == 0 @_kou1[p] = 1 @_kou2[p] = 1 @_ind[k1][p] = @_ind[p1][p] @_ind[k2][p] = @_ind[p2][p] for i2 in 0 ... @_len[p1] if @_ind[p2][p] == @_ind[p1][i2] @_ind[k1][i2] = @_ind[p1][i2] @_kou1[i2] = 1 sw = 0 break end end sw = 1 for i2 in 0 ... @_len[p2] if @_ind[p1][p] == @_ind[p2][i2] @_ind[k2][i2] = @_ind[p2][i2] @_kou2[i2] = 1 sw = 0 break end end end end sw = 0 i2 = 0 i3 = 0 while sw == 0 while sw == 0 and i2 < @_len[p1] if @_kou1[i2] == 0 sw = 1 else i2 += 1 end end sw = 0 while sw == 0 and i3 < @_len[p2] if @_kou2[i3] == 0 sw = 1 else i3 += 1 end end if i2 < @_len[p1] and i3 < @_len[p2] @_ind[k1][i2] = @_ind[p2][i3] @_ind[k2][i3] = @_ind[p1][i2] sw = 0 i2 += 1 i3 += 1 else sw = 1 end end end end end ################################################################### # 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と # 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ # の2つの遺伝子の位置を交換する.この操作を,選択した点よ # り右にあるすべての遺伝子に対して実施する # 2 4 1 3 6 5 2 4 5 3 6 1 # * → → ・・・・・ # 3 2 5 4 1 6 3 2 1 4 5 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) #******************************************************************/ def C_part(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_part)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_part)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 p = Integer(rand(0) * @_len[p1]) if p >= @_len[p1] p = @_len[p1] - 1 end for i2 in 0 ... @_len[p1] @_ind[k1][i2] = @_ind[p1][i2] @_ind[k2][i2] = @_ind[p2][i2] end for i2 in p ... @_len[p1] sw = 0 lv = @_ind[k1][i2] for i3 in 0 ... @_len[p1] if @_ind[k2][i2] == @_ind[k1][i3] @_ind[k1][i2] = @_ind[k1][i3] @_ind[k1][i3] = lv sw = 1 break end end sw = 0 for i3 in 0 ... @_len[p1] if lv == @_ind[k2][i3] @_ind[k2][i3] = @_ind[k2][i2] @_ind[k2][i2] = lv sw = 1 break end end end end end end ################################################################### # 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の # 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 # の遺伝子を親2の遺伝子の出現順序に並べ替える. # 2 4 1 3 6 5 2 4 1 3 5 6 # * → # 3 2 5 4 1 6 3 2 5 4 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_seq(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_seq)") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_seq)") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 p = Integer(rand(0) * (@_len[p1] - 1)) if p >= @_len[p1]-1 p = @_len[p1] - 2 end for i2 in 0 ... p+1 @_ind[k1][i2] = @_ind[p1][i2] @_ind[k2][i2] = @_ind[p2][i2] end pp = 0 for i2 in p+1 ... @_len[p1] sw = 0 i3 = pp while i3 < @_len[p2] and sw == 0 i4 = p + 1 while i4 < @_len[p1] and sw == 0 if @_ind[p2][i3] == @_ind[p1][i4] sw = 1 pp = i3 + 1 @_ind[k1][i2] = @_ind[p1][i4] end i4 += 1 end i3 += 1 end end pp = 0 for i2 in p+1 ... @_len[p2] sw = 0 i3 = pp while i3 < @_len[p1] and sw == 0 i4 = p + 1 while i4 < @_len[p2] and sw == 0 if @_ind[p1][i3] == @_ind[p2][i4] sw = 1 pp = i3 + 1 @_ind[k2][i2] = @_ind[p2][i4] end i4 += 1 end i3 += 1 end end end end end ################################################################### # 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の順序に従って,他の親の遺伝子 # を並べ替える # 2 4 1 3 6 5 2 4 1 3 6 5 # * * → # 3 2 5 4 1 6 4 2 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_useq(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair =Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_useq)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_useq)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 for i2 in 0 ... @_len[p1] @_ind[k1][i2] = @_ind[p1][i2] @_ind[k2][i2] = @_ind[p2][i2] if rand(0) < 0.5 @_kou1[i2] = 0 else @_kou1[i2] = 1 end end p = 0 for i2 in 0 ... @_len[p1] if @_kou1[i2] > 0 sw = 0 i3 = p while i3 < @_len[p2] and sw == 0 i4 = 0 while i4 < @_len[p1] and sw == 0 if @_ind[p2][i3] == @_ind[p1][i4] and @_kou1[i4] > 0 sw = 1 p = i3 + 1 @_ind[k1][i2] = @_ind[p1][i4] end i4 += 1 end i3 += 1 end end end p = 0 for i2 in 0 ... @_len[p3] if @_kou1[i2] > 0 sw = 0 i3 = p while i3 < @_len[p1] and sw == 0 i4 = 0 while i4 < @_len[p2] and sw == 0 if @_ind[p1][i3] == @_ind[p2][i4] and @_kou1[i4] > 0 sw = 1 p = i3 + 1 @_ind[k2][i2] = @_ind[p2][i4] end i4 += 1 end i3 += 1 end end end end end end ################################################################### # 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の位置に,他の親の同じ遺伝子を # 配置する.残りの遺伝子は,親と同じ順序に配置する. # 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 # * * → → # 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_upos(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) # 初期設定とデータのチェック pair = Integer(@_max_ch / 2) if @_dup_a != 0 print("***error 交叉方法が不適当 (C_upos)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_upos)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p2] # 交叉 for i2 in 0 ... @_len[p1] @_kou1[i2] = 1 if rand(0) < 0.5 @_kou1[i2] = 1 end if @_kou1[i2] > 0 @_ind[k1][i2] = @_ind[p2][i2] @_ind[k2][i2] = @_ind[p1][i2] end end p = 0 for i2 in 0 ... @_len[p1] sw = 0 for i3 in 0 ... @_len[p1] if @_kou1[i3] > 0 and @_ind[p1][i2] == @_ind[k1][i3] sw = 1 break end end if sw == 0 for i3 in p ... @_len[p1] if @_kou1[i3] == 0 @_ind[k1][i3] = @_ind[p1][i2] p = i3 + 1 sw = 1 break end end end end p = 0 for i2 in 0 ... @_len[p2] sw = 0 for i3 in 0 ... @_len[p2] if @_kou1[i3] > 0 and @_ind[p2][i2] == @_ind[k2][i3] sw = 1 break end end if sw == 0 for i3 in p ... @_len[p2] if @_kou1[i3] == 0 @_ind[k2][i3] = @_ind[p2][i2] p = i3 + 1 sw = 1 break end end end end end end end ################################################################### # 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は # 0~(max_len-1)である必要がある) # (0) エッジマップを作成する.エッジマップとは,2つの親 # を見て,ノードがどこに接続されているのかを表すもの # であり,例えば,2つの親が, # [A B C D E F] # [B D C A E F] # である場合は, # A B F C E # B A C D F # C B D A # D C E B # E D F A # F A E B # となる. # (1) 両親の2つの出発点の内1つで初期化する.ランダムま # たはステップ(4)の基準に従って選ぶ(現在のノード) # (2) エッジマップから,現在のノードを除く # (3) 現在のノードが接続先のノードを持っていたら,(4)に # 進む.さもなければ,(5)に進む # (4) 現在のノードが持っている接続先ノードの内,最も少な # い接続先ノードを持ったノードを選択し(同じ条件の場 # 合は,ランダム),それを現在のノードとし,(2)に進む # (5) 未接続のノードが残っていればランダムに選択し,(2)に # 戻る.さもなければ,終了する # kosa : 交叉確率 # k_method : 選択方法 # =-1 ランダム(default) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_edge(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) e = Array.new(2) k0 = 0 # 初期設定とデータのチェック pair = @_max_ch if @_dup_a != 0 print("***error 交叉方法が不適当 (C_edge)\n") end if @_min_len > 0 print("***error 遺伝子長は固定長でなければならない (C_edge)\n") end # 交叉 for i1 in 0 ... pair # 交叉しない場合 if rand(0) > kosa C_copy(1, 1) # 交叉する場合 else # 親の選択 p1 = Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 p2 = Select(k_method, k_bias, k_step) if p1 != p2 sw = 1 end end # 遺伝子長 k = Position(-1) @_pi_w[k] = 1 @_len[k] = @_len[p1] # エッジマップの初期化 for i2 in 0 ... @_len[k] @_edge[i2][0] = 0 for i3 in 1 ... 5 @_edge[i2][i3] = -1 end end # 交叉 # エッジマップの作成 for i2 in 0 ... @_len[k] sw = 0 for i3 in 0 ... @_len[k] if i2 == @_ind[p1][i3] sw = 1 if i3 == 0 e[0] = @_ind[p1][@_len[k]-1] e[1] = @_ind[p1][1] else if i3 == @_len[k]-1 e[0] = @_ind[p1][i3-1] e[1] = @_ind[p1][0] else e[0] = @_ind[p1][i3-1] e[1] = @_ind[p1][i3+1] end end for i4 in 0 ... 2 @_edge[i2][0] += 1 @_edge[i2][@_edge[i2][0]] = e[i4] end break end end sw = 0 for i3 in 0 ... @_len[k] if i2 == @_ind[p2][i3] sw = 1 if i3 == 0 e[0] = @_ind[p2][@_len[k]-1] e[1] = @_ind[p2][1] else if i3 == @_len[k]-1 e[0] = @_ind[p2][i3-1] e[1] = @_ind[p2][0] else e[0] = @_ind[p2][i3-1] e[1] = @_ind[p2][i3+1] end end for i4 in 0 ... 2 sw = 1 for i5 in 1 ... @_edge[i2][0]+1 if @_edge[i2][i5] == e[i4] sw = 2 break end end if sw == 1 @_edge[i2][0] += 1 @_edge[i2][@_edge[i2][0]] = e[i4] end end break end end end # 交叉の実行 # 出発点の決定 k1 = @_ind[p1][0] k2 = @_ind[p2][0] if @_edge[k1][0] == @_edge[k2][0] kk = k1 if rand(0) > 0.5 kk = k2 end else kk = k2 if @_edge[k1][0] < @_edge[k2][0] kk = k2 end end @_ind[k][0] = kk p = 1 while p < @_len[k] # ノードの除去 for i2 in 0 ... @_len[k] sw = 0 if @_edge[i2][0] > 0 for i3 in 1 ... 5 if @_edge[i2][i3] == kk sw = 1 @_edge[i2][i3] = -1 @_edge[i2][0] -= 1 break end end end end # 次の現在ノードの選択 min = 10 num = 0 for i2 in 1 ... 5 if @_edge[kk][i2] >= 0 k1 = @_edge[kk][i2] if @_edge[k1][0] >= 0 and @_edge[k1][0] < min num = 1 min = @_edge[k1][0] k0 = k1 else if @_edge[k1][0] == min num += 1 end end end end if num > 1 k1 = Integer(rand(0) * num) + 1 if k1 > num k1 = num end k2 = 0 k0 = -1 i2 = 1 while i2 <= 4 and k0 < 0 if @_edge[kk][i2] >= 0 if @_edge[@_edge[kk][i2]][0] == min k2 += 1 if k1 == k2 k0 = @_edge[kk][i2] end end end i2 += 1 end else if num <= 0 num = 0 for i2 in 0 ... @_len[k] if i2 != kk and @_edge[i2][0] >= 0 num += 1 end end if num <= 0 print("***error invalid data (C_edge)\n") else k1 = Integer(rand(0) * num) + 1 if k1 > num k1 = num end k2 = 0 k0 = -1 i2 = 0 while i2 < @_len[k] and k0 < 0 if i2 != kk and @_edge[i2][0] >= 0 k2 += 1 if k1 == k2 k0 = i2 end end i2 += 1 end end end end @_edge[kk][0] = -1 @_ind[k][p] = k0 kk = k0 p += 1 end end end end ############################################################## # 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に # 同じ遺伝子のグループがない限り実行されない.たとえば # ***abcd** # *cdab**** # のような両親の時実行され,以下の4つの子供が生成され # る) # ***cdab** # *abcd**** # ***badc** # *dcba**** # 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 # 供が生成される可能性があるので,子供の数としてこの値 # 以上のデータを入力しておく必要がある. # kosa : 交叉確率 # count : 1つのペアーに対する交差回数(default=10) ############################################################## def C_sub(kosa, count = 10) t22 = 0 # 初期設定とデータのチェック if (4*count*@_size*(@_size-1)) > @_max_ch print("***error 子供が多すぎる (C_sub)\n") end # 交叉 for i1 in 0 ... @_size-1 # 親1 p1 = Position(i1) if p1 >= 0 for i2 in i1 ... @_size # 親2 p2 = Position(i2) if p2 >= 0 # 交叉しない場合 if rand(0) > kosa C_copy(2, 1) # 交叉する場合 else # 交叉回数の制御 for i3 in 0 ... count # 交叉位置の決定(点の後ろで交叉) # 親1の交叉位置 t11 = Integer(rand(0) * @_len[p1]) if t11 > (@_len[p1]-1) t11 = @_len[p1] - 1 end sw = 0 while sw == 0 t12 = Integer(rand(0) * @_len[p1]) if t12 > (@_len[p1]-1) t12 = @_len[p1] - 1 end if t12 != t11 sw = 1 end end if t11 > t12 k1 = t11 t11 = t12 t12 = k1 end # 親2の交叉位置 sw = 0 t21 = -1 i4 = 0 while i4 < @_len[p2] and t21 < 0 i5 = t11 while i5 <= t12 and t21 < 0 if @_ind[p2][i4] == @_ind[p1][i5] t21 = i4 end i5 += 1 end i4 += 1 end if t21 >= 0 t22 = t21 + t12 - t11 if t22 < @_len[p2] sw = 1 i4 = t21 + 1 while i4 <= t22 and sw > 0 sw = 0 i5 = t11 while i5 <= t12 and sw == 0 if @_ind[p2][i4] == @_ind[p1][i5] sw = 1 end i5 += 1 end i4 += 1 end end end # 交叉の実行 if sw > 0 k1 = Position(-1) @_pi_w[k1] = 1 @_len[k1] = @_len[p1] k2 = Position(-1) @_pi_w[k2] = 1 @_len[k2] = @_len[p1] k3 = Position(-1) @_pi_w[k3] = 1 @_len[k3] = @_len[p2] k4 = Position(-1) @_pi_w[k4] = 1 @_len[k4] = @_len[p2] for i4 in 0 ... t11 @_ind[k1][i4] = @_ind[p1][i4] @_ind[k2][i4] = @_ind[p1][i4] end for i4 in t11 ... t12+1 @_ind[k1][i4] = @_ind[p2][t21+i4-t11] @_ind[k2][i4] = @_ind[p2][t22-i4+t11] end for i4 in t12+1 ... @_len[p1] @_ind[k1][i4] = @_ind[p1][i4] @_ind[k2][i4] = @_ind[p1][i4] end for i4 in 0 ... t21 @_ind[k3][i4] = @_ind[p2][i4] @_ind[k4][i4] = @_ind[p2][i4] end for i4 in t21 ... t22+1 @_ind[k3][i4] = @_ind[p1][t11+i4-t21] @_ind[k4][i4] = @_ind[p1][t12-i4+t21] end for i4 in t22+1 ... @_len[p2] @_ind[k3][i4] = @_ind[p2][i4] @_ind[k4][i4] = @_ind[p2][i4] end end end end end end end end end ####################################### # 突然変異(対立遺伝子との置き換え) # pr : 突然変異率 ####################################### def M_alle(pr) # データのチェックと初期設定 if @_dup_a == 0 print("***error 突然変異方法が不適当 (M_alle)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 for i2 in 0 ... @_len[i1] if rand(0) <= pr lid = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l) if lid > @_allele_u lid = @_allele_u end if lid != @_ind[i1][i2] @_ind[i1][i2] = lid end end end end end end ###################################################################### # 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に # 移動する) # pr : 突然変異率 ###################################################################### def M_move(pr) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 位置の決定 # p1 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end # p2 p2 = p1 sw = 0 while sw == 0 p2 = Integer(rand(0) * @_len[i1]) if p2 >= @_len[i1] p2 = @_len[i1] - 1 end if p2 != p1 sw = 1 end end # 実行 if p2 > p1 ld = @_ind[i1][p2] i2 = p2 while i2 > p1 @_ind[i1][i2] = @_ind[i1][i2-1] i2 -= -1 end @_ind[i1][p1] = ld else ld = @_ind[i1][p2] for i2 in p2 ... p1-1 @_ind[i1][i2] = @_ind[i1][i2+1] end @_ind[i1][p1-1] = ld end end end end ######################################################## # 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ######################################################## def M_inv(pr, wd = 0) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間の決定 if wd == 0 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end sw = 0 p2 = p1 while sw == 0 p2 = Integer(rand(0) * @_len[i1]) if p2 >= @_len[i1] p2 = @_len[i1] - 1 end if p2 != p1 sw = 1 end end if p1 > p2 p = p1 p1 = p2 p2 = p end else p1 = @_len[i1] while p1 > @_len[i1]-2 p1 = Integer(rand(0) * @_len[i1]) end p2 = p1 + wd - 1 if p2 >= @_len[i1] p2 = @_len[i1] - 1 end end # 実行 sw = 0 while sw == 0 lid = @_ind[i1][p1] @_ind[i1][p1] = @_ind[i1][p2] @_ind[i1][p2] = lid p1 += 1 p2 -= 1 if p1 >= p2 sw = 1 end end end end end ###################################################################### # 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_scram(pr, wd = 0) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間の決定 if wd == 0 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end sw = 0 p2 = p1 while sw == 0 p2 = Integer(rand(0) * @_len[i1]) if p2 >= @_len[i1] p2 = @_len[i1] - 1 end if p2 != p1 sw = 1 end end if p1 > p2 p = p1 p1 = p2 p2 = p end else p1 = @_len[i1] while p1 > @_len[i1]-2 p1 = Integer(rand(0) * @_len[i1]) end p2 = p1 + wd - 1 if p2 >= @_len[i1] p2 = @_len[i1] - 1 end end # 実行 for i2 in p1 ... p2+1 p = Integer(rand(0) * (p2 - p1 + 1) + p1) if p > p2 p = p2 end ld = @_ind[i1][i2] @_ind[i1][i2] = @_ind[i1][p] @_ind[i1][p] = ld end end end end ###################################################################### # 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし # 重複部分はそのままとする) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_chg(pr, wd = 0) for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間等の決定([p1,p2]と[p3,p4]の入れ替え) # p1 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end # p3 sw = 0 p3 = p1 while sw == 0 p3 = Integer(rand(0) * @_len[i1]) if p3 >= @_len[i1] p3 = @_len[i1] - 1 end if p3 != p1 sw = 1 end end # 小さい方をp1,p2にする if p1 > p3 p = p1 p1 = p3 p3 = p end # p4, p2 p4 = p1 + wd - 1 if wd == 0 p4 = Integer(rand(0) * (@_len[i1] - p3)) + p3 end if p4 >= @_len[i1] p4 = @_len[i1] - 1 end p2 = p1 + (p4 - p3) # 重複部分のチェック if p2 >= p3 p = p3 - 1 p3 = p2 + 1 p2 = p p4 = p3 + (p2 - p1) end # 実行 p = p3 for i2 in p1 ... p2+1 ld = @_ind[i1][i2] @_ind[i1][i2] = @_ind[i1][p] @_ind[i1][p] = ld p += 1 end end end end ###################################################################### # 突然変異(重複.2点間の遺伝子を他の位置にコピーする # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(deafult) ###################################################################### def M_dup(pr, wd = 0) # データのチェック if @_dup_a == 0 print("***error 突然変異方法が不適当 (M_dup)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 区間の決定([p1,p2]を[p3,p4]にコピー) # p1 p1 = Integer(rand(0) * @_len[i1]) if p1 >= @_len[i1] p1 = @_len[i1] - 1 end # p3 sw = 0 p3 = p1 while sw == 0 p3 = Integer(rand(0) * @_len[i1]) if p3 >= @_len[i1] p3 = @_len[i1] - 1 end if p3 != p1 sw = 1 end end # 区間を決める p2 = p1 p4 = p1 if p3 > p1 p4 = p3 + wd - 1 if wd == 0 p4 = Integer(rand(0) * (@_len[i1] - p3)) + p3 end if p4 >= @_len[i1] p4 = @_len[i1] - 1 end p2 = p1 + (p4 - p3) else p2 = p1 + wd - 1 if wd == 0 p2 = Integer(rand(0) * (@_len[i1] - p1)) + p1 end if p2 >= @_len[i1] p2 = @_len[i1] - 1 end p4 = p3 + (p2 - p1) # 実行 end p = p4 i2 = p2 while i2 > p1-1 @_ind[i1][p] = @_ind[i1][i2] p -= 1 i2 -= 1 end end end end ###################################################### # 突然変異(摂動.値をある量だけ変化させる) # pr : 突然変異率 # method : =0 正規分布(default) # =1 一様分布 # m : 平均または一様分布の下限(default=0.0) # s : 標準偏差または一様分布の上限(default=1.0) ###################################################### def M_per(pr, method = 0, m = 0.0, s = 1.0) wd = 0.0 # データのチェックと初期設定 if @_dup_a == 0 print("***error 突然変異方法が不適当 (M_per)\n") end if method > 0 wd = s - m end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 for i2 in 0 ... @_len[i1] if rand(0) <= pr if method == 0 w = normalvariate(m, s) else w = rand(0) * wd if rand(0) < 0.5 w = -w end end x1 = float(@_ind[i1][i2]) + w if x1 > @_allele_u x1 = @_allele_u else if x1 < @_allele_l x1 = @_allele_l end end @_ind[i1][i2] = Integer(x1) end end end end end ############################################## # 突然変異(挿入.ある長さの遺伝子を挿入する) # pr : 突然変異率 # wd : >0 幅を固定 # =0 幅をランダム(default) ############################################## def M_ins(pr, wd = 0) # データのチェック if @_dup_a == 0 or @_min_len < 0 print("***error 突然変異方法が不適当 (M_ins)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 挿入位置の決定 p = Integer(rand(0) * (@_len[i1] + 1)) if p > @_len[i1] p = @_len[i1] end # 挿入する遺伝子長の決定 l = wd if wd == 0 l = Integer(rand(0) * (@_max_len - @_len[i1] + 1)) end if l > @_max_len-@_len[i1] l = @_max_len - @_len[i1] else if l <= 0 l = 1 end end # 実行 # 挿入場所の確保 if p < @_len[i1] i2 = @_len[i1] + l - 1 while i2 > p-1 @_ind[i1][i2] = @_ind[i1][i2-l] i2 -= 1 end end # 挿入場所の遺伝子の決定 for i2 in p ... p+l ld = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l) if ld > @_allele_u ld = @_allele_u end @_ind[i1][i2] = ld end @_len[i1] += l end end end ############################################## # 突然変異(削除.ある長さの遺伝子を削除する) # pr : 突然変異率 # wd : >0 幅を固定 # =0 幅をランダム(default) ############################################## def M_del(pr, wd = 0) # データのチェック if @_dup_a == 0 or @_min_len < 0 print("***error 突然変異方法が不適当 (M_del)\n") end # 実行 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 and rand(0) <= pr # 削除位置の決定 p = Integer(rand(0) * @_len[i1]) if p >= @_len[i1] p = @_len[i1] - 1 end # 削除する遺伝子長の決定 max = @_len[i1] - p if @_len[i1]-@_min_len < @_len[i1]-p max = @_len[i1] - @_min_len end l = wd if wd == 0 l = Integer(rand(0) * max + 1) end if l > max l = max end # 実行 for i2 in 0 ... @_len[i1]-p-l @_ind[i1][p+i2] = @_ind[i1][p+i2+l] end @_len[i1] -= l end end end ###################################################################### # 淘汰(エリート・ルーレット選択) # elite : エリートで残す個体数(default=0) # s_method : ルーレット板の作成方法(default=1) # =0 適応度をそのまま使用 # =1 最小値からの差(ただし,α以下の場合はα) # =2 評価値に順位をつけ,減少率βで線形化 # s_bias : α,または,method=2の場合は初期値(default=0) # s_step : β(default=1) ###################################################################### def S_roul(elite = 0, s_method = 1, s_bias = 0.0, s_step = 1.0) count = 0 k = 0 n = 0 # 値のチェックと初期設定 if s_method != 0 and s_method != 2 s_method = 1 end if elite > @_size print("***error エリートで残す数が多すぎる (S_roul)\n") end if s_method == 2 and s_step <= 0.0 s_step = 1.0 end for i1 in 0 ... @_size+@_max_ch @_s_w[i1] = 0 end # 重複個体を削除 if @_dup_s == 0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 0 for i2 in i1+1 ... @_size+@_max_ch if @_pi_w[i2] > 0 and @_len[i1] == @_len[i2] sw = 0 for i3 in 0 ... @_len[i1] if @_ind[i1][i3] != @_ind[i2][i3] sw = 1 break end end if sw == 0 @_pi_w[i2] = 0 end end end end end end for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 n += 1 end end if n < 0 or (@_dup_s == 0 and n < @_size) print("***error 残す個体がない (S_roul)\n") end # 淘汰して残す個体を選ぶ # エリートの選択 sw = 0 while k < elite and k < n and sw == 0 max = -1 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] > 1 and @_s_w[i1] == 0 if max < 0 or @_pi[i1] > @_pi[max] max = i1 end end end if max < 0 sw = 1 else @_s_w[max] = 1 k += 1 end end # ルーレット選択 while count < @_size+@_max_ch and k < @_size p = Select(s_method, s_bias, s_step) if @_dup_s == 0 and @_s_w[p] > 0 count += 1 else count = 0 @_s_w[p] += 1 k += 1 end end # 選択に失敗した場合の処理 if @_dup_s == 0 and k < @_size i1 = 0 while i1 < @_size+@_max_ch and k < @_size if @_pi_w[i1] > 1 and @_s_w[i1] == 0 @_s_w[i1] = 1 k += 1 end i1 += 1 end end # 複数回選択されたものの処理 for i1 in 0 ... @_size+@_max_ch if @_s_w[i1] == 0 @_pi_w[i1] = 0 end end for i1 in 0 ... @_size+@_max_ch if @_s_w[i1] > 0 if @_s_w[i1] > 1 for i2 in 2 ... @_s_w[i1]+1 k = Position(-1) @_len[k] = @_len[i1] @_pi_w[k] = 2 @_pi[k] = @_pi[i1] for i3 in 0 ... @_len[i1] @_ind[k][i3] = @_ind[i1][i3] end end end end end end end ####################### # クラスFunctionの定義 ####################### class Function < Species ###################################### # コンストラクタ # name1 : Species定義ファイル名 # name2 : Function定義ファイル名 ###################################### def initialize(name1, name2) super(name1) # 親のコンストラクタ # 基本データの入力 inn = open(name2, "r") s = inn.gets().split(" ") @_out_lvl = Integer(s[1]) # 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負の時はファイル) @_out_m = Integer(s[3]) # 出力方法 # =0 : すべてを出力 # =1 : 最大適応度の個体だけを出力 s = inn.gets().split(" ") @_o_file = s[1] # 出力ファイル名 @_out_d = Integer(s[3]) # 表示間隔 s = inn.gets().split(" ") @_kosa_m = Integer(s[1]) # 交叉方法 # =-1 : 交叉を使用しない # =0 : 親のコピー # =1 : 多点交叉 # =2 : 一様交叉 # =3 : 平均化交叉 @_kosa = Float(s[3]) # 交叉確率 @_k_point = Integer(s[5]) # 交差点の数(負の時は,1から-k_point間のランダム) @_k_vr = Integer(s[7]) # =0 : 両親とも同じ位置で交叉 # =1 : 両親が異なる位置で交叉(遺伝子長は可変) @_k_method = Integer(s[9]) # 交叉の時の親の選択方法 # =-1 : ランダム # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 @_k_bias = Float(s[11]) # α,または,method=2の場合は初期値 @_k_step = Float(s[13]) # β s = inn.gets().split(" ") @_mute_m = Integer(s[1]) # 突然変異方法 # =-1 : 突然変異を使用しない # =0 : 対立遺伝子への置換 # =1 : 移動 # =2 : 逆位 # =3 : スクランブル # =4 : 転座 # =5 : 重複 # =6 : 摂動 @_mute = Float(s[3]) # 突然変異率 @_wd = Integer(s[5]) # 突然変異に使用する部分遺伝子長 @_m_mean = Float(s[7]) # 摂動の平均値 @_m_std = Float(s[9]) # 摂動の標準偏差 s = inn.gets().split(" ") @_elite = Integer(s[1]) # エリート選択で残す数 @_s_method = Integer(s[3]) # ルーレット板の作成方法 # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 @_s_bias = Float(s[5]) # α,または,s_method=2の場合は初期値 @_s_step = Float(s[7]) # β s = inn.gets().split(" ") @_max_gen = Integer(s[1]) # 最大世代交代数 @_cv = 1.0 / (2.0 ** Float(@_max_len) - 1.0) # 2進数を10進数の変換する係数 inn.close() end ############### # 全体の制御 ############### def Control() gen = 1 # 初期集団の発生 Init_std() # 評価 Adap() # 出力 print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n") if @_out_lvl.abs() > 0 Output(gen) end # 世代交代 for gen in 2 ... @_max_gen+1 # 交叉 if @_kosa_m == 0 C_copy() # 親のコピー elsif @_kosa_m == 1 C_point(@_kosa, @_k_point) # 多点交叉 elsif @_kosa_m == 2 C_uniform(@_kosa) # 一様交叉 elsif @_kosa_m == 3 C_mean(@_kosa) # 平均化交叉 end # 突然変異 if @_mute_m == 0 M_alle(@_mute) # 対立遺伝子への置換 elsif @_mute_m == 1 M_move(@_mute) # 移動 elsif @_mute_m == 2 M_inv(@_mute, @_wd) # 逆位 elsif @_mute_m == 3 M_scram(@_mute, @_wd) # スクランブル elsif @_mute_m == 4 M_chg(@_mute, @_wd) # 転座 elsif @_mute_m == 5 M_dup(@_mute, @_wd) # 重複 elsif @_mute_m == 6 M_per(@_mute, @_wd, @_m_mean, @_m_std) # 摂動 end # 適応度 Adap() # 淘汰 S_roul(@_elite) # 出力 if gen%@_out_d == 0 print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n") end if @_out_lvl.abs() > 0 if gen%@_out_lvl.abs() == 0 Output(gen) end end end gen -= 1 k1 = @_out_m @_out_m = 0 print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n") Output(gen) @_out_m = k1 end ################ # 適応度の計算 ################ def Adap() n = 0 @_max = 0.0 @_max_n = -1 @_mean = 0.0 for i1 in 0 ... @_size+@_max_ch if @_pi_w[i1] == 1 x = 0.0 y = 0.0 i2 = @_len[i1] - 1 while i2 > -1 if @_ind[i1][i2] > 0 x += 2.0 ** y end y += 1.0 i2 -= 1 end x *= @_cv @_pi[i1] = Math.sin(3.0*x) + 0.5 * Math.sin(9.0*x) + Math.sin(15.0*x+50.0) @_pi_w[i1] = 2 end if @_pi_w[i1] > 0 @_mean += @_pi[i1] n += 1 if @_max_n < 0 or @_pi[i1] > @_max @_max = @_pi[i1] @_max_n = i1 end end end @_mean /= n end ############################# # 結果の出力 # gen : 現在の世代番号 ############################# def Output(gen) k = 0 pr = -1 if @_out_lvl >= 0 print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer($stdin.gets()) end if pr != 0 # 出力先の決定と評価値の出力 if pr > 0 out = $stdout $stdin.gets() else now = String(Time.now) out = open(@_o_file, "a") out.print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + " 時間 " + now + "\n") end # 詳細出力 sw = 0 for i1 in 0 ... @_size+@_max_ch if (@_pi_w[i1] > 1) and (@_out_m == 0 or (@_out_m == 1 and i1 == @_max_n)) out.print(String(i1) + " allele") for i2 in 0 ... @_len[i1] out.print(" " + String(@_ind[i1][i2])) end x = 0.0 y = 0.0 i2 = @_len[i1] - 1 while i2 > -1 if @_ind[i1][i2] > 0 x += 2.0 ** y end y += 1.0 i2 -= 1 end x *= @_cv out.print(" x " + String(x) + " y " + String(@_pi[i1]) + "\n") if pr > 0 k += 1 if k == pr $stdin.gets() k = 0 end end end end if pr < 0 out.close() end end end end # 入力ミス if ARGV[0] == nil print("***error ファイル名を入力して下さい\n") # 入力OK else # データの数と入力データファイル名の入力 line = gets() n = Integer(line) # データの数 i_file1 = Array.new(n) i_file2 = Array.new(n) for i1 in 0 ... n line = gets() a = line.split(" ") i_file1[i1] = a[0] i_file2[i1] = a[1] end # 実行(乱数の初期値を変える) for i1 in 0 ... n print("\n+++++ケース " + String(i1+1) + "+++++\n") srand(1000 * i1 + 1234567); fn = Function.new(i_file1[i1], i_file2[i1]) fn.Control() end end =begin ------------------ケーススタディデータ(data_cf.txt)------ 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt ------------------Species記述データ(data1_f.txt)--------- 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 ------------------Function記述データ(data2_f.txt)-------- 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 =end
# -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * from datetime import * /***********************************/ /* 遺伝的アルゴリズムによるTSPの解 */ /* coded by Y.Suganuma */ /***********************************/ ###################### # クラスSpeciesの定義 ###################### class Species : ######################### # コンストラクタ # name : ファイル名 ######################### def __init__(self, name) : # データの入力 inn = open(name, "r") s = inn.readline().split() self.allele_u = int(s[1]) # 対立遺伝子上限 self.allele_l = int(s[3]) # 対立遺伝子下限 s = inn.readline().split() self.max_len = int(s[1]) # 最大遺伝子長 self.min_len = int(s[3]) # 最小遺伝子長(負の時は,最大遺伝子長で固定) s = inn.readline().split() self.dup_a = int(s[1]) # 遺伝子の重複 # =0 : 重複を許さない # =1 : 重複を許す self.dup_s = int(s[3]) # 個体の重複(同じ染色体の個体) # =0 : 重複を許さない # =1 : 重複を許す s = inn.readline().split() self.size = int(s[1]) # 個体総数 self.max_ch = int(s[3]) # 子供の数の最大値 # データのチェック if self.size <= 0 : print("***error 個体総数≦0 (Constructor)") if self.max_ch < 0 : print("***error 子供の数<0 (Constructor)") if self.max_len <= 0 or self.min_len == 0 : print("***error 遺伝子長≦0 (Constructor)") if self.max_len < self.min_len : print("***error 最大遺伝子長<最小遺伝子長 (Constructor)") if self.allele_u <= self.allele_l : print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)") kind = self.allele_u - self.allele_l + 1 if self.dup_a == 0 and self.max_len > kind : print("***error 遺伝子の重複を防ぐことはできない (Constructor)") # 領域の確保 num = self.size + self.max_ch self.ind = np.empty((num, self.max_len), np.int) # 集団(個体の集まり) self.edge = np.empty((self.max_len, 5), np.int) # エッジ組み替え交叉用ワークエリア self.pi = np.empty(num, np.float) # 適応度 self.ro = np.empty(num, np.float) # ルーレット板 self.len = np.empty(num, np.int) # 各個体の遺伝子長 self.kou1 = np.empty(self.max_len, np.int) # 交叉・突然変異用作業場所1 self.kou2 = np.empty(self.max_len, np.int) # 交叉・突然変異用作業場所2 self.s_w = np.empty(num, np.int) # 淘汰用指標(選択された回数) self.pi_w = np.empty(num, np.int) # 適応度計算指標 # =0 : 未使用 # =1 : 適応度計算前(突然変異はこの個体だけに適用) # =2 : 適応度計算済み(交叉時に親とみなす) self.max = -inf # 最大適応度 self.mean = 0.0 # 平均適応度 self.max_n = -1 # 最大適応度の個体番号 ################################################## # 場所を探す # n : >=0 : n番目の親を捜す # -1 : 空いている場所を探す # return : 親の場所,または,空いている場所 # (存在しないときは負の値) ################################################## def Position(self, n) : k = -1 sw = 0 # 空いている場所を探す if n < 0 : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 0 : k = i1 break if k < 0 : print("***error 空いている場所がない --Position--") # n番目の親(pi_w[i]=2)を捜す else : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 2 : k += 1 if k == n : sw = 1 k = i1 break return k ################################################################### # 個体の選択 # method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # bias : α,または,method=2の場合は初期値(default=0) # step : β(default=1) # return : 個体番号 ################################################################### def Select(self, method, bias, step) : sum = 0.0 # ルーレット板の用意 # ランダム if method == -1 : n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : n += 1 sum = 1.0 / n for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = sum # 評価値をそのまま利用 elif method == 0 : n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : sum += self.pi[i1] n += 1 if fabs(sum) > 1.0e-10 : sum = 1.0 / fabs(sum) for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = self.pi[i1] * sum else : sum = 1.0 / n for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = sum # 最小値からの差 elif method == 1 : min = -1 n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : n += 1 if min < 0 or self.pi[i1] < self.pi[min] : min = i1 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = self.pi[i1] - self.pi[min] if self.ro[i1] < bias : self.ro[i1] = bias sum += self.ro[i1] if sum > 1.0e-10 : sum = 1.0 / sum for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] *= sum else : sum = 1.0 / n for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = sum # 線形化 elif method == 2 : n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = -1.0 n += 1 else : self.ro[i1] = 1.0 sw = 0 sum = bias while sw == 0 : min = -1 for i1 in range(0, self.size+self.max_ch) : if self.ro[i1] < 0.0 and (min < 0 or self.pi[i1] < self.pi[min]) : min = i1 if min < 0 : sw = 1 else : self.ro[min] = sum sum += self.step sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n) for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] *= sum sum = 0.0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : sum += self.ro[i1] self.ro[i1] = sum # 選択 x = random() sw = 0 k = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : if x <= self.ro[i1] : sw = 1 k = i1 break return k ################### # 標準的な初期設定 ################### def Init_std(self) : # 初期設定 for i1 in range(0, self.size+self.max_ch) : if i1 < self.size : self.pi_w[i1] = 1 # 適応度の計算前 else : self.pi_w[i1] = 0 # 未使用 # 遺伝子の決定 for i1 in range(0, self.size) : sw1 = 0 length = 0 while sw1 == 0 : # 遺伝子長の決定 if self.min_len < 0 : length = self.max_len else : length = int(random() * (self.max_len - self.min_len + 1) + self.min_len) if length > self.max_len : length = self.max_len self.len[i1] = length # 遺伝子の決定 for i2 in range(0, length) : sw2 = 0 while sw2 == 0 : lid = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l) if lid > self.allele_u : lid = self.allele_u self.ind[i1][i2] = lid # 重複遺伝子のチェック sw2 = 1 if self.dup_a == 0 : for i3 in range(0, i2) : if lid == self.ind[i1][i3] : sw2 = 0 break # 重複個体のチェック sw1 = 1 if self.dup_s == 0 : for i2 in range(0, i1) : if self.len[i1] == self.len[i2] : sw2 = 0 for i3 in range(0, self.len[i1]) : if self.ind[i1][i3] != self.ind[i2][i3] : sw2 = 1 break if sw2 == 0 : sw1 = 0 break #################################################### # 標準的な出力 # sw : 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負はファイル) # out_m : 出力方法 # =0 : すべての個体を出力 # =1 : 最大適応度の個体だけを出力 # gen : 現在の世代番号 # name : 出力ファイル名 #################################################### def Out_std(self, sw, out_m, gen, name) : k = 0 pr = -1 if sw >= 0 : pr = int(input(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ")) if pr != 0 : # 出力先の決定と評価値の出力 if pr > 0 : out = sys.stdout input("") else : now = datetime.today().time().isoformat() out = open(name, "a") out.write("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean) + " 時間 " + now + "\n") # 詳細出力 for i1 in range(0, self.size+self.max_ch) : if (self.pi_w[i1] > 1) and (out_m == 0 or (out_m == 1 and i1 == self.max_n)) : out.write(str(i1) + " allele") for i2 in range(0, self.len[i1]) : out.write(" " + str(self.ind[i1][i2])) out.write(" value " + str(self.pi[i1]) + "\n") if pr > 0 : k += 1 if k == pr : input("") k = 0 if pr < 0 : out.close() ################################################################### # 交叉(親のコピー) # method : =2 : 有性(2つの親から2つの子供)(default) # =1 : 1つの親から1つの子供 # pair : method=2 の時は親のペア数(default=max_ch/2) # method=1 の時は親の数(=子供の数) # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_copy(self, method = 2, pair = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータチェック if method != 1 : method = 2 if pair <= 0 : if method == 2 : pair = int(self.max_ch / 2) else : pair = self.max_ch else : if method == 2 and 2*pair > self.max_ch or method == 1 and pair > self.max_ch : print("***error 子供が多すぎる (C_copy)") # 実行 for i1 in range(0, pair) : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # コピー for i2 in range(0, method) : p = p2 if i2 == 0 : p = p1 k = self.Position(-1) self.len[k] = self.len[p] self.pi_w[k] = 1 for i3 in range(0, self.len[k]) : self.ind[k][i3] = self.ind[p][i3] ################################################################### # 交叉(多点交叉) # kosa : 交叉確率 # k_point : 交叉点の数(default=1) # (負の時は,1から-k_point間のランダム) # k_vr : =0 : 両親とも同じ位置で交叉(default) # =1 : 両親が異なる位置で交叉(遺伝子長は可変) # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_point(self, kosa, k_point = 1, k_vr = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) : mn = 0 # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a == 0 : print("***error 交叉方法が不適当 (C_point)") abs_p = abs(k_point) if abs_p == 0 or abs_p > self.max_len-1 or self.min_len > 0 and abs_p > self.min_len-1 : print("***error 交叉点の数が不適当 (C_point)") if k_vr > 0 and self.min_len < 0 : print("***error 遺伝子長は可変でなければならない (C_point)") # 交叉 num = k_point for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 交叉位置の数の決定 if k_point < 0 : num = int(random() * abs_p + 1) if num > abs_p : num = abs_p # 交叉位置の決定(点の後ろで交叉) for i2 in range(0, num) : # 親1の交叉位置 sw = 0 while sw == 0 : sw = 1 self.kou1[i2] = int(random() * (self.len[p1] - 1)) if self.kou1[i2] > self.len[p1]-2 : self.kou1[i2] = self.len[p1] - 2 if k_vr == 0 and self.kou1[i2] > self.len[p2]-2 : self.kou1[i2] = self.len[p2] - 2 for i3 in range(0, i2) : if self.kou1[i3] == self.kou1[i2] : sw = 0 break # 親2の交叉位置 if k_vr > 0 : sw = 0 while sw == 0 : sw = 1 self.kou2[i2] = int(random() * (self.len[p2] - 1)) if self.kou2[i2] > self.len[p2]-2 : self.kou2[i2] = self.len[p2] - 2 for i3 in range(0, i2) : if self.kou2[i3] == self.kou2[i2] : sw = 0 break # 交叉の実行 # 親1のt11からt12を子1のc1へコピー # 親2のt21からt22を子2のc2へコピー # 次は, # 親1のt11からt12を子2のc2へコピー # 親2のt21からt22を子1のc1へコピー # ・・・・・ c1 = 0 c2 = 0 t11 = 0 t21 = 0 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] for i2 in range(0, num+1) : # 次の交叉位置を求める if i2 == num : # 最後 t12 = self.len[p1] t22 = self.len[p2] else : # 親1 t12 = self.max_len for i3 in range(0, num) : if self.kou1[i3] >= 0 and self.kou1[i3] <= t12 : t12 = self.kou1[i3] mn = i3 self.kou1[mn] = -1 t12 += 1 # 親2 if k_vr == 0 : t22 = t12 else : t22 = self.max_len for i3 in range(0, num) : if self.kou2[i3] >= 0 and self.kou2[i3] <= t22 : t22 = self.kou2[i3] mn = i3 self.kou2[mn] = -1 t22 += 1 # 指定箇所のコピー for i3 in range(t11, t12) : if i2%2 == 0 : if c1 < self.max_len : self.ind[k1][c1] = self.ind[p1][i3] c1 += 1 else : if c2 < self.max_len : self.ind[k2][c2] = self.ind[p1][i3] c2 += 1 for i3 in range(t21, t22) : if i2%2 == 0 : if c2 < self.max_len : self.ind[k2][c2] = self.ind[p2][i3] c2 += 1 else : if c1 < self.max_len : self.ind[k1][c1] = self.ind[p2][i3] c1 += 1 # 交叉位置の移動 t11 = t12 t21 = t22 ################################################################### # 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, # 親1,0であれば親2の遺伝子を子1が受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_uniform(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a == 0 : print("***error 交叉方法が不適当 (C_uniform)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_uniform)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 for i2 in range(0, self.len[p1]) : if random() > 0.5 : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] else : self.ind[k1][i2] = self.ind[p2][i2] self.ind[k2][i2] = self.ind[p1][i2] ################################################################### # 交叉(平均化交叉.2つの親の平均値を受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_mean(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_mean)") # 交叉 for i1 in range(0, self.max_ch) : # 交叉しない場合 if random() > kosa : self.C_copy(1, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k = self.Position(-1) self.len[k] = self.len[p1] self.pi_w[k] = 1 # 交叉 for i2 in range(0, self.len[k]) : self.ind[k][i2] = int((self.ind[p1][i2] + self.ind[p2][i2]) / 2) ################################################################### # 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を # そのまま各子供が選択する.その位置にある親2(1)の遺伝 # 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 # ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 # 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り # 返し,残りの遺伝子については,子1(2)は,親2(1)の # 遺伝子をその順番通りに受け継ぐ) # 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 # * → → # 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_cycle(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_cycle)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_cycle)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 初期設定 for i2 in range(0, self.len[p1]) : self.kou1[i2] = 0 self.kou2[i2] = 0 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 sw = 0 while sw == 0 : sw = 1 p = int(random() * self.len[p1]) if p >= self.len[p1] : p = self.len[p1] - 1 if self.kou1[p] == 0 and self.kou2[p] == 0 : self.kou1[p] = 1 self.kou2[p] = 1 self.ind[k1][p] = self.ind[p1][p] self.ind[k2][p] = self.ind[p2][p] for i2 in range(0, self.len[p1]) : if self.ind[p2][p] == self.ind[p1][i2] : self.ind[k1][i2] = self.ind[p1][i2] self.kou1[i2] = 1 sw = 0 break sw = 1 for i2 in range(0, self.len[p2]) : if self.ind[p1][p] == self.ind[p2][i2] : self.ind[k2][i2] = self.ind[p2][i2] self.kou2[i2] = 1 sw = 0 break sw = 0 i2 = 0 i3 = 0 while sw == 0 : while sw == 0 and i2 < self.len[p1] : if self.kou1[i2] == 0 : sw = 1 else : i2 += 1 sw = 0 while sw == 0 and i3 < self.len[p2] : if self.kou2[i3] == 0 : sw = 1 else : i3 += 1 if i2 < self.len[p1] and i3 < self.len[p2] : self.ind[k1][i2] = self.ind[p2][i3] self.ind[k2][i3] = self.ind[p1][i2] sw = 0 i2 += 1 i3 += 1 else : sw = 1 ################################################################### # 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と # 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ # の2つの遺伝子の位置を交換する.この操作を,選択した点よ # り右にあるすべての遺伝子に対して実施する # 2 4 1 3 6 5 2 4 5 3 6 1 # * → → ・・・・・ # 3 2 5 4 1 6 3 2 1 4 5 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) #******************************************************************/ def C_part(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_part)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_part)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 p = int(random() * self.len[p1]) if p >= self.len[p1] : p = self.len[p1] - 1 for i2 in range(0, self.len[p1]) : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] for i2 in range(p, self.len[p1]) : sw = 0 lv = self.ind[k1][i2] for i3 in range(0, self.len[p1]) : if self.ind[k2][i2] == self.ind[k1][i3] : self.ind[k1][i2] = self.ind[k1][i3] self.ind[k1][i3] = lv sw = 1 break sw = 0 for i3 in range(0, self.len[p1]) : if lv == self.ind[k2][i3] : self.ind[k2][i3] = self.ind[k2][i2] self.ind[k2][i2] = lv sw = 1 break ################################################################### # 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の # 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 # の遺伝子を親2の遺伝子の出現順序に並べ替える. # 2 4 1 3 6 5 2 4 1 3 5 6 # * → # 3 2 5 4 1 6 3 2 5 4 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_seq(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_seq)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_seq)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 p = int(random() * (self.len[p1] - 1)) if p >= self.len[p1]-1 : p = self.len[p1] - 2 for i2 in range(0, p+1) : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] pp = 0 for i2 in range(p+1, self.len[p1]) : sw = 0 i3 = pp while i3 < self.len[p2] and sw == 0 : i4 = p + 1 while i4 < self.len[p1] and sw == 0 : if self.ind[p2][i3] == self.ind[p1][i4] : sw = 1 pp = i3 + 1 self.ind[k1][i2] = self.ind[p1][i4] i4 += 1 i3 += 1 pp = 0 for i2 in range(p+1, self.len[p2]) : sw = 0 i3 = pp while i3 < self.len[p1] and sw == 0 : i4 = p + 1 while i4 < self.len[p2] and sw == 0 : if self.ind[p1][i3] == self.ind[p2][i4] : sw = 1 pp = i3 + 1 self.ind[k2][i2] = self.ind[p2][i4] i4 += 1 i3 += 1 ################################################################### # 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の順序に従って,他の親の遺伝子 # を並べ替える # 2 4 1 3 6 5 2 4 1 3 6 5 # * * → # 3 2 5 4 1 6 4 2 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_useq(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair =int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_useq)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_useq)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 for i2 in range(0, self.len[p1]) : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] if random() < 0.5 : self.kou1[i2] = 0 else : self.kou1[i2] = 1 p = 0 for i2 in range(0, self.len[p1]) : if self.kou1[i2] > 0 : sw = 0 i3 = p while i3 < self.len[p2] and sw == 0 : i4 = 0 while i4 < self.len[p1] and sw == 0 : if self.ind[p2][i3] == self.ind[p1][i4] and self.kou1[i4] > 0 : sw = 1 p = i3 + 1 self.ind[k1][i2] = self.ind[p1][i4] i4 += 1 i3 += 1 p = 0 for i2 in range(0, self.len[p3]) : if self.kou1[i2] > 0 : sw = 0 i3 = p while i3 < self.len[p1] and sw == 0 : i4 = 0 while i4 < self.len[p2] and sw == 0 : if self.ind[p1][i3] == self.ind[p2][i4] and self.kou1[i4] > 0 : sw = 1 p = i3 + 1 self.ind[k2][i2] = self.ind[p2][i4] i4 += 1 i3 += 1 ################################################################### # 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の位置に,他の親の同じ遺伝子を # 配置する.残りの遺伝子は,親と同じ順序に配置する. # 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 # * * → → # 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_upos(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_upos)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_upos)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 for i2 in range(0, self.len[p1]) : self.kou1[i2] = 1 if random() < 0.5 : self.kou1[i2] = 1 if self.kou1[i2] > 0 : self.ind[k1][i2] = self.ind[p2][i2] self.ind[k2][i2] = self.ind[p1][i2] p = 0 for i2 in range(0, self.len[p1]) : sw = 0 for i3 in range(0, self.len[p1]) : if self.kou1[i3] > 0 and self.ind[p1][i2] == self.ind[k1][i3] : sw = 1 break if sw == 0 : for i3 in range(p, self.len[p1]) : if self.kou1[i3] == 0 : self.ind[k1][i3] = self.ind[p1][i2] p = i3 + 1 sw = 1 break p = 0 for i2 in range(0, self.len[p2]) : sw = 0 for i3 in range(0, self.len[p2]) : if self.kou1[i3] > 0 and self.ind[p2][i2] == self.ind[k2][i3] : sw = 1 break if sw == 0 : for i3 in range(p, self.len[p2]) : if self.kou1[i3] == 0 : self.ind[k2][i3] = self.ind[p2][i2] p = i3 + 1 sw = 1 break ################################################################### # 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は # 0~(max_len-1)である必要がある) # (0) エッジマップを作成する.エッジマップとは,2つの親 # を見て,ノードがどこに接続されているのかを表すもの # であり,例えば,2つの親が, # [A B C D E F] # [B D C A E F] # である場合は, # A : B F C E # B : A C D F # C : B D A # D : C E B # E : D F A # F : A E B # となる. # (1) 両親の2つの出発点の内1つで初期化する.ランダムま # たはステップ(4)の基準に従って選ぶ(現在のノード) # (2) エッジマップから,現在のノードを除く # (3) 現在のノードが接続先のノードを持っていたら,(4)に # 進む.さもなければ,(5)に進む # (4) 現在のノードが持っている接続先ノードの内,最も少な # い接続先ノードを持ったノードを選択し(同じ条件の場 # 合は,ランダム),それを現在のノードとし,(2)に進む # (5) 未接続のノードが残っていればランダムに選択し,(2)に # 戻る.さもなければ,終了する # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_edge(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : e = np.empty(2, np.int) k0 = 0 # 初期設定とデータのチェック pair = self.max_ch if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_edge)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_edge)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(1, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k = self.Position(-1) self.pi_w[k] = 1 self.len[k] = self.len[p1] # エッジマップの初期化 for i2 in range(0, self.len[k]) : self.edge[i2][0] = 0 for i3 in range(1, 5) : self.edge[i2][i3] = -1 # 交叉 # エッジマップの作成 for i2 in range(0, self.len[k]) : sw = 0 for i3 in range(0, self.len[k]) : if i2 == self.ind[p1][i3] : sw = 1 if i3 == 0 : e[0] = self.ind[p1][self.len[k]-1] e[1] = self.ind[p1][1] else : if i3 == self.len[k]-1 : e[0] = self.ind[p1][i3-1] e[1] = self.ind[p1][0] else : e[0] = self.ind[p1][i3-1] e[1] = self.ind[p1][i3+1] for i4 in range(0, 2) : self.edge[i2][0] += 1 self.edge[i2][self.edge[i2][0]] = e[i4] break sw = 0 for i3 in range(0, self.len[k]) : if i2 == self.ind[p2][i3] : sw = 1 if i3 == 0 : e[0] = self.ind[p2][self.len[k]-1] e[1] = self.ind[p2][1] else : if i3 == self.len[k]-1 : e[0] = self.ind[p2][i3-1] e[1] = self.ind[p2][0] else : e[0] = self.ind[p2][i3-1] e[1] = self.ind[p2][i3+1] for i4 in range(0, 2) : sw = 1 for i5 in range(1, self.edge[i2][0]+1) : if self.edge[i2][i5] == e[i4] : sw = 2 break if sw == 1 : self.edge[i2][0] += 1 self.edge[i2][self.edge[i2][0]] = e[i4] break # 交叉の実行 # 出発点の決定 k1 = self.ind[p1][0] k2 = self.ind[p2][0] if self.edge[k1][0] == self.edge[k2][0] : kk = k1 if random() > 0.5 : kk = k2 else : kk = k2 if self.edge[k1][0] < self.edge[k2][0] : kk = k2 self.ind[k][0] = kk p = 1 while p < self.len[k] : # ノードの除去 for i2 in range(0, self.len[k]) : sw = 0 if self.edge[i2][0] > 0 : for i3 in range(1, 5) : if self.edge[i2][i3] == kk : sw = 1 self.edge[i2][i3] = -1 self.edge[i2][0] -= 1 break # 次の現在ノードの選択 min = 10 num = 0 for i2 in range(1, 5) : if self.edge[kk][i2] >= 0 : k1 = self.edge[kk][i2] if self.edge[k1][0] >= 0 and self.edge[k1][0] < min : num = 1 min = self.edge[k1][0] k0 = k1 else : if self.edge[k1][0] == min : num += 1 if num > 1 : k1 = int(random() * num) + 1 if k1 > num : k1 = num k2 = 0 k0 = -1 i2 = 1 while i2 <= 4 and k0 < 0 : if self.edge[kk][i2] >= 0 : if self.edge[self.edge[kk][i2]][0] == min : k2 += 1 if k1 == k2 : k0 = self.edge[kk][i2] i2 += 1 else : if num <= 0 : num = 0 for i2 in range(0, self.len[k]) : if i2 != kk and self.edge[i2][0] >= 0 : num += 1 if num <= 0 : print("***error invalid data (C_edge)") else : k1 = int(random() * num) + 1 if k1 > num : k1 = num k2 = 0 k0 = -1 i2 = 0 while i2 < self.len[k] and k0 < 0 : if i2 != kk and self.edge[i2][0] >= 0 : k2 += 1 if k1 == k2 : k0 = i2 i2 += 1 self.edge[kk][0] = -1 self.ind[k][p] = k0 kk = k0 p += 1 ############################################################## # 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に # 同じ遺伝子のグループがない限り実行されない.たとえば # ***abcd** # *cdab**** # のような両親の時実行され,以下の4つの子供が生成され # る) # ***cdab** # *abcd**** # ***badc** # *dcba**** # 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 # 供が生成される可能性があるので,子供の数としてこの値 # 以上のデータを入力しておく必要がある. # kosa : 交叉確率 # count : 1つのペアーに対する交差回数(default=10) ############################################################## def C_sub(self, kosa, count = 10) : t22 = 0 # 初期設定とデータのチェック if (4*count*self.size*(self.size-1)) > self.max_ch : print("***error 子供が多すぎる (C_sub)") # 交叉 for i1 in range(0, self.size-1) : # 親1 p1 = self.Position(i1) if p1 >= 0 : for i2 in range(i1, self.size) : # 親2 p2 = self.Position(i2) if p2 >= 0 : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 交叉回数の制御 for i3 in range(0, count) : # 交叉位置の決定(点の後ろで交叉) # 親1の交叉位置 t11 = int(random() * self.len[p1]) if t11 > (self.len[p1]-1) : t11 = self.len[p1] - 1 sw = 0 while sw == 0 : t12 = int(random() * self.len[p1]) if t12 > (self.len[p1]-1) : t12 = self.len[p1] - 1 if t12 != t11 : sw = 1 if t11 > t12 : k1 = t11 t11 = t12 t12 = k1 # 親2の交叉位置 sw = 0 t21 = -1 i4 = 0 while i4 < self.len[p2] and t21 < 0 : i5 = t11 while i5 <= t12 and t21 < 0 : if self.ind[p2][i4] == self.ind[p1][i5] : t21 = i4 i5 += 1 i4 += 1 if t21 >= 0 : t22 = t21 + t12 - t11 if t22 < self.len[p2] : sw = 1 i4 = t21 + 1 while i4 <= t22 and sw > 0 : sw = 0 i5 = t11 while i5 <= t12 and sw == 0 : if self.ind[p2][i4] == self.ind[p1][i5] : sw = 1 i5 += 1 i4 += 1 # 交叉の実行 if sw > 0 : k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p1] k3 = self.Position(-1) self.pi_w[k3] = 1 self.len[k3] = self.len[p2] k4 = self.Position(-1) self.pi_w[k4] = 1 self.len[k4] = self.len[p2] for i4 in range(0, t11) : self.ind[k1][i4] = self.ind[p1][i4] self.ind[k2][i4] = self.ind[p1][i4] for i4 in range(t11, t12+1) : self.ind[k1][i4] = self.ind[p2][t21+i4-t11] self.ind[k2][i4] = self.ind[p2][t22-i4+t11] for i4 in range(t12+1, self.len[p1]) : self.ind[k1][i4] = self.ind[p1][i4] self.ind[k2][i4] = self.ind[p1][i4] for i4 in range(0, t21) : self.ind[k3][i4] = self.ind[p2][i4] self.ind[k4][i4] = self.ind[p2][i4] for i4 in range(t21, t22+1) : self.ind[k3][i4] = self.ind[p1][t11+i4-t21] self.ind[k4][i4] = self.ind[p1][t12-i4+t21] for i4 in range(t22+1, self.len[p2]) : self.ind[k3][i4] = self.ind[p2][i4] self.ind[k4][i4] = self.ind[p2][i4] ####################################### # 突然変異(対立遺伝子との置き換え) # pr : 突然変異率 ####################################### def M_alle(self, pr) : # データのチェックと初期設定 if self.dup_a == 0 : print("***error 突然変異方法が不適当 (M_alle)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : for i2 in range(0, self.len[i1]) : if random() <= pr : lid = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l) if lid > self.allele_u : lid = self.allele_u if lid != self.ind[i1][i2] : self.ind[i1][i2] = lid ###################################################################### # 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に # 移動する) # pr : 突然変異率 ###################################################################### def M_move(self, pr) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 位置の決定 # p1 p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 # p2 p2 = p1 sw = 0 while sw == 0 : p2 = int(random() * self.len[i1]) if p2 >= self.len[i1] : p2 = self.len[i1] - 1 if p2 != p1 : sw = 1 # 実行 if p2 > p1 : ld = self.ind[i1][p2] for i2 in range(p2, p1, -1) : self.ind[i1][i2] = self.ind[i1][i2-1] self.ind[i1][p1] = ld else : ld = self.ind[i1][p2] for i2 in range(p2, p1-1) : self.ind[i1][i2] = self.ind[i1][i2+1] self.ind[i1][p1-1] = ld ######################################################## # 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ######################################################## def M_inv(self, pr, wd = 0) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間の決定 if wd == 0 : p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 sw = 0 p2 = p1 while sw == 0 : p2 = int(random() * self.len[i1]) if p2 >= self.len[i1] : p2 = self.len[i1] - 1 if p2 != p1 : sw = 1 if p1 > p2 : p = p1 p1 = p2 p2 = p else : p1 = self.len[i1] while p1 > self.len[i1]-2 : p1 = int(random() * self.len[i1]) p2 = p1 + wd - 1 if p2 >= self.len[i1] : p2 = self.len[i1] - 1 # 実行 sw = 0 while sw == 0 : lid = self.ind[i1][p1] self.ind[i1][p1] = self.ind[i1][p2] self.ind[i1][p2] = lid p1 += 1 p2 -= 1 if p1 >= p2 : sw = 1 ###################################################################### # 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_scram(self, pr, wd = 0) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間の決定 if wd == 0 : p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 sw = 0 p2 = p1 while sw == 0 : p2 = int(random() * self.len[i1]) if p2 >= self.len[i1] : p2 = self.len[i1] - 1 if p2 != p1 : sw = 1 if p1 > p2 : p = p1 p1 = p2 p2 = p else : p1 = self.len[i1] while p1 > self.len[i1]-2 : p1 = int(random() * self.len[i1]) p2 = p1 + wd - 1 if p2 >= self.len[i1] : p2 = self.len[i1] - 1 # 実行 for i2 in range(p1, p2+1) : p = int(random() * (p2 - p1 + 1) + p1) if p > p2 : p = p2 ld = self.ind[i1][i2] self.ind[i1][i2] = self.ind[i1][p] self.ind[i1][p] = ld ###################################################################### # 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし # 重複部分はそのままとする) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_chg(self, pr, wd = 0) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間等の決定([p1,p2]と[p3,p4]の入れ替え) # p1 p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 # p3 sw = 0 p3 = p1 while sw == 0 : p3 = int(random() * self.len[i1]) if p3 >= self.len[i1] : p3 = self.len[i1] - 1 if p3 != p1 : sw = 1 # 小さい方をp1,p2にする if p1 > p3 : p = p1 p1 = p3 p3 = p # p4, p2 p4 = p1 + wd - 1 if wd == 0 : p4 = int(random() * (self.len[i1] - p3)) + p3 if p4 >= self.len[i1] : p4 = self.len[i1] - 1 p2 = p1 + (p4 - p3) # 重複部分のチェック if p2 >= p3 : p = p3 - 1 p3 = p2 + 1 p2 = p p4 = p3 + (p2 - p1) # 実行 p = p3 for i2 in range(p1, p2+1) : ld = self.ind[i1][i2] self.ind[i1][i2] = self.ind[i1][p] self.ind[i1][p] = ld p += 1 ###################################################################### # 突然変異(重複.2点間の遺伝子を他の位置にコピーする # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(deafult) ###################################################################### def M_dup(self, pr, wd = 0) : # データのチェック if self.dup_a == 0 : print("***error 突然変異方法が不適当 (M_dup)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間の決定([p1,p2]を[p3,p4]にコピー) # p1 p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 # p3 sw = 0 p3 = p1 while sw == 0 : p3 = int(random() * self.len[i1]) if p3 >= self.len[i1] : p3 = self.len[i1] - 1 if p3 != p1 : sw = 1 # 区間を決める p2 = p1 p4 = p1 if p3 > p1 : p4 = p3 + wd - 1 if wd == 0 : p4 = int(random() * (self.len[i1] - p3)) + p3 if p4 >= self.len[i1] : p4 = self.len[i1] - 1 p2 = p1 + (p4 - p3) else : p2 = p1 + wd - 1 if wd == 0 : p2 = int(random() * (self.len[i1] - p1)) + p1 if p2 >= self.len[i1] : p2 = self.len[i1] - 1 p4 = p3 + (p2 - p1) # 実行 p = p4 for i2 in range(p2, p1-1, -1) : self.ind[i1][p] = self.ind[i1][i2] p -= 1 ###################################################### # 突然変異(摂動.値をある量だけ変化させる) # pr : 突然変異率 # method : =0 : 正規分布(default) # =1 : 一様分布 # m : 平均または一様分布の下限(default=0.0) # s : 標準偏差または一様分布の上限(default=1.0) ###################################################### def M_per(self, pr, method = 0, m = 0.0, s = 1.0) : wd = 0.0 # データのチェックと初期設定 if self.dup_a == 0 : print("***error 突然変異方法が不適当 (M_per)") if method > 0 : wd = s - m # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : for i2 in range(0, self.len[i1]) : if random() <= pr : if method == 0 : w = normalvariate(m, s) else : w = random() * wd if random() < 0.5 : w = -w x1 = float(self.ind[i1][i2]) + w if x1 > self.allele_u : x1 = self.allele_u else : if x1 < self.allele_l : x1 = self.allele_l self.ind[i1][i2] = int(x1) ############################################## # 突然変異(挿入.ある長さの遺伝子を挿入する) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ############################################## def M_ins(self, pr, wd = 0) : # データのチェック if self.dup_a == 0 or self.min_len < 0 : print("***error 突然変異方法が不適当 (M_ins)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 挿入位置の決定 p = int(random() * (self.len[i1] + 1)) if p > self.len[i1] : p = self.len[i1] # 挿入する遺伝子長の決定 l = wd if wd == 0 : l = int(random() * (self.max_len - self.len[i1] + 1)) if l > self.max_len-self.len[i1] : l = self.max_len - self.len[i1] else : if l <= 0 : l = 1 # 実行 # 挿入場所の確保 if p < self.len[i1] : for i2 in range(self.len[i1]+l-1, p-1, -1) : self.ind[i1][i2] = self.ind[i1][i2-l] # 挿入場所の遺伝子の決定 for i2 in range(p, p+l) : ld = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l) if ld > self.allele_u : ld = self.allele_u self.ind[i1][i2] = ld self.len[i1] += l ############################################## # 突然変異(削除.ある長さの遺伝子を削除する) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ############################################## def M_del(self, pr, wd = 0) : # データのチェック if self.dup_a == 0 or self.min_len < 0 : print("***error 突然変異方法が不適当 (M_del)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 削除位置の決定 p = int(random() * self.len[i1]) if p >= self.len[i1] : p = self.len[i1] - 1 # 削除する遺伝子長の決定 max = self.len[i1] - p if self.len[i1]-self.min_len < self.len[i1]-p : max = self.len[i1] - self.min_len l = wd if wd == 0 : l = int(random() * max + 1) if l > max : l = max # 実行 for i2 in range(0, self.len[i1]-p-l) : self.ind[i1][p+i2] = self.ind[i1][p+i2+l] self.len[i1] -= l ###################################################################### # 淘汰(エリート・ルーレット選択) # elite : エリートで残す個体数(default=0) # s_method : ルーレット板の作成方法(default=1) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # s_bias : α,または,method=2の場合は初期値(default=0) # s_step : β(default=1) ###################################################################### def S_roul(self, elite = 0, s_method = 1, s_bias = 0.0, s_step = 1.0) : count = 0 k = 0 n = 0 # 値のチェックと初期設定 if s_method != 0 and s_method != 2 : s_method = 1 if elite > self.size : print("***error エリートで残す数が多すぎる (S_roul)") if s_method == 2 and s_step <= 0.0 : s_step = 1.0 for i1 in range(0, self.size+self.max_ch) : self.s_w[i1] = 0 # 重複個体を削除 if self.dup_s == 0 : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 0 : for i2 in range(i1+1, self.size+self.max_ch) : if self.pi_w[i2] > 0 and self.len[i1] == self.len[i2] : sw = 0 for i3 in range(0, self.len[i1]) : if self.ind[i1][i3] != self.ind[i2][i3] : sw = 1 break if sw == 0 : self.pi_w[i2] = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : n += 1 if n < 0 or self.dup_s == 0 and n < self.size : print("***error 残す個体がない (S_roul)") # 淘汰して残す個体を選ぶ # エリートの選択 sw = 0 while k < elite and k < n and sw == 0 : max = -1 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 and self.s_w[i1] == 0 : if max < 0 or self.pi[i1] > self.pi[max] : max = i1 if max < 0 : sw = 1 else : self.s_w[max] = 1 k += 1 # ルーレット選択 while count < self.size+self.max_ch and k < self.size : p = self.Select(s_method, s_bias, s_step) if self.dup_s == 0 and self.s_w[p] > 0 : count += 1 else : count = 0 self.s_w[p] += 1 k += 1 # 選択に失敗した場合の処理 if self.dup_s == 0 and k < self.size : i1 = 0 while i1 < self.size+self.max_ch and k < self.size : if self.pi_w[i1] > 1 and self.s_w[i1] == 0 : self.s_w[i1] = 1 k += 1 i1 += 1 # 複数回選択されたものの処理 for i1 in range(0, self.size+self.max_ch) : if self.s_w[i1] == 0 : self.pi_w[i1] = 0 for i1 in range(0, self.size+self.max_ch) : if self.s_w[i1] > 0 : if self.s_w[i1] > 1 : for i2 in range(2, self.s_w[i1]+1) : k = self.Position(-1) self.len[k] = self.len[i1] self.pi_w[k] = 2 self.pi[k] = self.pi[i1] for i3 in range(0, self.len[i1]) : self.ind[k][i3] = self.ind[i1][i3] #################### # クラスTSPの定義 #################### class TSP ( Species ) : ###################################### # コンストラクタ # name1 : Species定義ファイル名 # name2 : TSP定義ファイル名 ###################################### def __init__(self, name1, name2) : Species.__init__(self, name1) # 親のコンストラクタ # 基本データの入力 inn = open(name2, "r") s = inn.readline().split() self.out_lvl = int(s[1]) # 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負の時はファイル) self.out_m = int(s[3]) # 出力方法 # =0 : すべてを出力 # =1 : 最大適応度の個体だけを出力 s = inn.readline().split() self.o_file = s[1] # 出力ファイル名 self.out_d = int(s[3]) # 表示間隔 s = inn.readline().split() self.kosa_m = int(s[1]) # 交叉方法 # =-1 : 交叉を使用しない # =0 : 親のコピー # =1 : 循環交叉 # =2 : 部分的交叉 # =3 : 順序交叉 # =4 : 一様順序交叉 # =5 : 一様位置交叉 # =6 : エッジ組み替え交叉 # =7 : サブツアー交叉 self.kosa = float(s[3]) # 交叉確率 self.k_point = int(s[5]) # 交差点の数(負の時は,1から-k_point間のランダム) self.k_vr = int(s[7]) # =0 : 両親とも同じ位置で交叉 # =1 : 両親が異なる位置で交叉(遺伝子長は可変) self.k_method = int(s[9]) # 交叉の時の親の選択方法 # =-1 : ランダム # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 self.k_bias = float(s[11]) # α,または,method=2の場合は初期値 self.k_step = float(s[13]) # β s = inn.readline().split() self.mute_m = int(s[1]) # 突然変異方法 # =-1 : 突然変異を使用しない # =0 : 移動 # =1 : 逆位 # =2 : スクランブル # =3 : 転座 self.mute = float(s[3]) # 突然変異率 self.wd = int(s[5]) # 突然変異に使用する部分遺伝子長 self.m_mean = float(s[7]) # 摂動の平均値 self.m_std = float(s[9]) # 摂動の標準偏差 s = inn.readline().split() self.elite = int(s[1]) # エリート選択で残す数 self.s_method = int(s[3]) # ルーレット板の作成方法 # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 self.s_bias = float(s[5]) # α,または,s_method=2の場合は初期値 self.s_step = float(s[7]) # β s = inn.readline().split() self.n_city = int(s[1]) # 都市の数 self.max_gen = int(s[3]) # 最大世代交代数 s = inn.readline().split() self.kinbo = int(s[1]) # 近傍探索(0:行わない,1:行う) self.neib = int(s[3]) # 近傍(2 or 3) s = inn.readline().split() self.sel = int(s[1]) # エッジの選択方法 # =0 : 最良のものを選択 # =1 : 最初のものを選択 if self.kinbo > 0 and self.neib != 2 and self.neib != 3 : print("***error 近傍の値が不適当") if self.n_city != self.max_len : print("***error 都市数が不適当") # 都市の位置データ self.city = np.empty((self.n_city, 2), np.int) for i1 in range(0, self.n_city) : s = inn.readline().split() self.city[i1][0] = int(s[0]) self.city[i1][1] = int(s[1]) # 距離テーブル self.rg = np.empty((self.n_city, self.n_city), np.int) for i1 in range(0, self.n_city) : for i2 in range(i1+1, self.n_city) : x = self.city[i2][0] - self.city[i1][0] y = self.city[i2][1] - self.city[i1][1] self.rg[i1][i2] = int(sqrt(x * x + y * y) + 0.5) for i1 in range(1, self.n_city) : for i2 in range(0, i1) : self.rg[i1][i2] = self.rg[i2][i1] inn.close() ############### # 全体の制御 ############### def Control(self) : gen = 1 # 初期集団の発生 self.Init_std() # 評価 if self.kinbo > 0 : self.Kinbo() else : self.Adap() # 出力 print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean)) if abs(self.out_lvl) > 0 : self.Output(gen) # 世代交代 for gen in range(2, self.max_gen+1) : # 交叉 if self.kosa_m == 0 : C_copy() # 親のコピー elif self.kosa_m == 1 : self.C_cycle(self.kosa) # 循環交叉 elif self.kosa_m == 2 : self.C_part(self.kosa) # 部分的交叉 elif self.kosa_m == 3 : self.C_seq(self.kosa) # 順序交叉 elif self.kosa_m == 4 : self.C_useq(self.kosa) # 一様順序交叉 elif self.kosa_m == 5 : self.C_upos(self.kosa) # 一様位置交叉 elif self.kosa_m == 6 : self.C_edge(self.kosa) # エッジ組み替え交叉 elif self.kosa_m == 7 : self.C_sub(self.kosa, self.k_point) # サブツアー交叉 # 突然変異 if self.mute_m == 0 : self.M_move(self.mute) # 移動 elif self.mute_m == 1 : self.M_inv(self.mute) # 逆位 elif self.mute_m == 2 : self.M_scram(self.mute) # スクランブル elif self.mute_m == 3 : self.M_chg(self.mute) # 転座 # 適応度 if self.kinbo > 0 : self.Kinbo() else : self.Adap() # 淘汰 self.S_roul(self.elite) # 出力 if gen%self.out_d == 0 : print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean)) if abs(self.out_lvl) > 0 : if gen%abs(self.out_lvl) == 0 : self.Output(gen) gen -= 1 k1 = self.out_m self.out_m = 0 print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean)) self.Output(gen) self.out_m = k1 ########################## # 距離の計算 # n_c : 都市の数 # p : 都市番号 # return : 距離(負) ########################## def Kyori(self, n_c, p) : r = 0 n1 = p[0] for i1 in range(1, n_c) : n2 = p[i1] r -= self.rg[n1][n2] n1 = n2 n2 = p[0] r -= self.rg[n1][n2] return r ################ # 適応度の計算 ################ def Adap(self) : k = 0 self.mean = 0.0 self.max = 0.0 self.max_n = -1 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : self.pi_w[i1] = 2 self.pi[i1] = self.Kyori(self.len[i1], self.ind[i1]) if self.pi_w[i1] > 0 : k += 1 self.mean += self.pi[i1] if self.max_n < 0 or self.pi[i1] > self.max : self.max = self.pi[i1] self.max_n = i1 if k > 0 : self.mean /= k ###################################### # エッジの入れ替え # n_city : 都市の数 # seq : 訪問する順番 # r_m : 距離の負値 # return : =0 : 改善がなかった # =1 : 改善があった ###################################### def Change(self, n_city, seq, r_m) : ch = 0 sw = 0 max = r_m[0] n3 = int(random() * (n_city - 2)) if n3 > n_city-3 : n3 = n_city - 3 # 2近傍 i1 = 0 while i1 <= n_city-3 and ch == 0 : if n3 == 0 : n1 = n_city - 2 else : n1 = n_city - 1 i2 = n3 + 2 while i2 <= n1 and ch == 0 : # 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 if i2 == n_city-1 : k2 = 0 else : k2 = i2 + 1 # 枝の入れ替え self.kou1[0] = seq[n3] k = 1 for i3 in range(k1, n3, -1) : self.kou1[k] = seq[i3] k += 1 nn = k2 while nn != n3 : self.kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 : nn = 0 # 評価 r = self.Kyori(n_city, self.kou1) if r > max : max = r sw = 1 for i3 in range(0, n_city) : self.kou2[i3] = self.kou1[i3] if self.sel > 0 : ch = 1 i2 += 1 n3 += 1 if n3 > n_city-3 : n3 = 0 i1 += 1 # 3近傍 if self.neib == 3 and ch == 0 : i1 = 0 while i1 <= n_city-3 and ch == 0 : n1 = n_city - 2 n2 = n_city - 1 i2 = n3 + 1 while i2 <= n1 and ch == 0 : i3 = i2 + 1 while i3 <= n2 and ch == 0 : # 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 k2 = k1 if i3 == n_city-1 : k2 = 0 else : k2 = i3 + 1 # 枝の入れ替えと評価 # 入れ替え(その1) self.kou1[0] = seq[n3] k = 1 for i4 in range(i2, n3, -1) : self.kou1[k] = seq[i4] k += 1 for i4 in range(k1, i2, -1) : self.kou1[k] = seq[i4] k += 1 nn = k2 while nn != n3 : self.kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 : nn = 0 # 評価(その1) r = self.Kyori(n_city, self.kou1) if r > max : max = r sw = 1 for i3 in range(0, n_city) : self.kou2[i3] = self.kou1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その2) self.kou1[0] = seq[n3] k = 1 for i4 in range(k1, i2, -1) : self.kou1[k] = seq[i4] k += 1 for i4 in range(n3+1, i2+1) : self.kou1[k] = seq[i4] k += 1 nn = k2 while nn != n3 : self.kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 : nn = 0 # 評価(その2) r = self.Kyori(n_city, self.kou1) if r > max : max = r sw = 1 for i3 in range(0, n_city) : self.kou2[i3] = self.kou1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その3) self.kou1[0] = seq[n3] k = 1 for i4 in range(i2+1, k1+1) : self.kou1[k] = seq[i4] k += 1 for i4 in range(i2, n3, -1) : self.kou1[k] = seq[i4] k += 1 nn = k2 while nn != n3 : self.kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 : nn = 0 # 評価(その3) r = self.Kyori(n_city, self.kou1) if r > max : max = r sw = 1 for i3 in range(0, n_city) : self.kou2[i3] = self.kou1[i3] if self.sel > 0 : ch = 1 # 入れ替え(その4) self.kou1[0] = seq[n3] k = 1 for i4 in range(i2+1, k1+1) : self.kou1[k] = seq[i4] k += 1 for i4 in range(n3+1, i2+1) : self.kou1[k] = seq[i4] k += 1 nn = k2 while nn != n3 : self.kou1[k] = seq[nn] k += 1 nn += 1 if nn > n_city-1 : nn = 0 # 評価(その4) r = self.Kyori(n_city, self.kou1) if r > max : max = r sw = 1 for i3 in range(0, n_city) : self.kou2[i3] = self.kou1[i3] if self.sel > 0 : ch = 1 i3 += 1 i2 += 1 n3 += 1 if n3 > n_city-3 : n3 = 0 i1 += 1 # 設定 if sw > 0 : r_m[0] = max for i1 in range(0, n_city) : seq[i1] = self.kou2[i1] return sw ############## # 近傍の探索 ############## def Kinbo(self) : k = 0 self.max = 0.0 self.max_n = -1 self.mean = 0.0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : self.pi_w[i1] = 2 sw = 1 r = self.Kyori(self.len[i1], self.ind[i1]) while sw > 0 : r = np.empty(1, np.int) sw = self.Change(self.len[i1], self.ind[i1], r) self.pi[i1] = r[0] if self.pi_w[i1] > 0 : k += 1 self.mean += self.pi[i1] if self.max_n < 0 or self.pi[i1] > self.max : self.max = self.pi[i1] self.max_n = i1 if k > 0 : self.mean /= k ############################# # 結果の出力 # gen : 現在の世代番号 ############################# def Output(self, gen) : k = 0 pr = -1 if self.out_lvl >= 0 : print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ", end=" ") pr = int(input()) if pr != 0 : # 出力先の決定と評価値の出力 if pr > 0 : out = sys.stdout input("") else : now = datetime.today().time().isoformat() out = open(self.o_file, "a") out.write("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean) + " 時間 " + now + "\n") # 巡回順序の出力 if self.out_m == 0 : for i1 in range(0, self.len[self.max_n]) : n = self.ind[self.max_n][i1] out.write(str(n) + " " + str(self.city[n][0]) + " " + str(self.city[n][1]) + "\n") if pr > 0 : k += 1 if k == pr : input("") k = 0 if pr < 0 : out.close() # 入力ミス if len(sys.argv) <= 1 : print("***error ファイル名を入力して下さい") # 入力OK else : # データの数と入力データファイル名の入力 inn = open(sys.argv[1], "r") ss = inn.readline() n = int(ss) # データの数 i_file1 = [] i_file2 = [] for i1 in range(0, n) : s = inn.readline().split() i_file1.append(s[0]) i_file2.append(s[1]) inn.close() # 実行(乱数の初期値を変える) for i1 in range(0, n) : print("\n+++++ケース " + str(i1+1) + "+++++") seed(1000 * i1 + 1234567); tsp = TSP(i_file1[i1], i_file2[i1]) tsp.Control() """ ----------------ケーススタディデータ(data_ct.txt)------ 3 data1_t.txt data2_t.txt data1_t.txt data2_t.txt data1_t.txt data2_t.txt ---------------Species記述データ(data1_t.txt)--------- 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 ---------------TSP記述データ(data2_t.txt)-------- 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 """
# -*- coding: UTF-8 -*- import numpy as np import sys from math import * from random import * from datetime import * ################################################################### # f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 # coded by Y.Suganuma ################################################################### ###################### # クラスSpeciesの定義 ###################### class Species : ######################### # コンストラクタ # name : ファイル名 ######################### def __init__(self, name) : # データの入力 inn = open(name, "r") s = inn.readline().split() self.allele_u = int(s[1]) # 対立遺伝子上限 self.allele_l = int(s[3]) # 対立遺伝子下限 s = inn.readline().split() self.max_len = int(s[1]) # 最大遺伝子長 self.min_len = int(s[3]) # 最小遺伝子長(負の時は,最大遺伝子長で固定) s = inn.readline().split() self.dup_a = int(s[1]) # 遺伝子の重複 # =0 : 重複を許さない # =1 : 重複を許す self.dup_s = int(s[3]) # 個体の重複(同じ染色体の個体) # =0 : 重複を許さない # =1 : 重複を許す s = inn.readline().split() self.size = int(s[1]) # 個体総数 self.max_ch = int(s[3]) # 子供の数の最大値 # データのチェック if self.size <= 0 : print("***error 個体総数≦0 (Constructor)") if self.max_ch < 0 : print("***error 子供の数<0 (Constructor)") if self.max_len <= 0 or self.min_len == 0 : print("***error 遺伝子長≦0 (Constructor)") if self.max_len < self.min_len : print("***error 最大遺伝子長<最小遺伝子長 (Constructor)") if self.allele_u <= self.allele_l : print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)") kind = self.allele_u - self.allele_l + 1 if self.dup_a == 0 and self.max_len > kind : print("***error 遺伝子の重複を防ぐことはできない (Constructor)") # 領域の確保 num = self.size + self.max_ch self.ind = np.empty((num, self.max_len), np.int) # 集団(個体の集まり) self.edge = np.empty((self.max_len, 5), np.int) # エッジ組み替え交叉用ワークエリア self.pi = np.empty(num, np.float) # 適応度 self.ro = np.empty(num, np.float) # ルーレット板 self.len = np.empty(num, np.int) # 各個体の遺伝子長 self.kou1 = np.empty(self.max_len, np.int) # 交叉・突然変異用作業場所1 self.kou2 = np.empty(self.max_len, np.int) # 交叉・突然変異用作業場所2 self.s_w = np.empty(num, np.int) # 淘汰用指標(選択された回数) self.pi_w = np.empty(num, np.int) # 適応度計算指標 # =0 : 未使用 # =1 : 適応度計算前(突然変異はこの個体だけに適用) # =2 : 適応度計算済み(交叉時に親とみなす) self.max = -inf # 最大適応度 self.mean = 0.0 # 平均適応度 self.max_n = -1 # 最大適応度の個体番号 ################################################## # 場所を探す # n : >=0 : n番目の親を捜す # -1 : 空いている場所を探す # return : 親の場所,または,空いている場所 # (存在しないときは負の値) ################################################## def Position(self, n) : k = -1 sw = 0 # 空いている場所を探す if n < 0 : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 0 : k = i1 break if k < 0 : print("***error 空いている場所がない --Position--") # n番目の親(pi_w[i]=2)を捜す else : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 2 : k += 1 if k == n : sw = 1 k = i1 break return k ################################################################### # 個体の選択 # method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # bias : α,または,method=2の場合は初期値(default=0) # step : β(default=1) # return : 個体番号 ################################################################### def Select(self, method, bias, step) : sum = 0.0 # ルーレット板の用意 # ランダム if method == -1 : n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : n += 1 sum = 1.0 / n for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = sum # 評価値をそのまま利用 elif method == 0 : n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : sum += self.pi[i1] n += 1 if fabs(sum) > 1.0e-10 : sum = 1.0 / fabs(sum) for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = self.pi[i1] * sum else : sum = 1.0 / n for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = sum # 最小値からの差 elif method == 1 : min = -1 n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : n += 1 if min < 0 or self.pi[i1] < self.pi[min] : min = i1 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = self.pi[i1] - self.pi[min] if self.ro[i1] < bias : self.ro[i1] = bias sum += self.ro[i1] if sum > 1.0e-10 : sum = 1.0 / sum for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] *= sum else : sum = 1.0 / n for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = sum # 線形化 elif method == 2 : n = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] = -1.0 n += 1 else : self.ro[i1] = 1.0 sw = 0 sum = bias while sw == 0 : min = -1 for i1 in range(0, self.size+self.max_ch) : if self.ro[i1] < 0.0 and (min < 0 or self.pi[i1] < self.pi[min]) : min = i1 if min < 0 : sw = 1 else : self.ro[min] = sum sum += self.step sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n) for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : self.ro[i1] *= sum sum = 0.0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : sum += self.ro[i1] self.ro[i1] = sum # 選択 x = random() sw = 0 k = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : if x <= self.ro[i1] : sw = 1 k = i1 break return k ################### # 標準的な初期設定 ################### def Init_std(self) : # 初期設定 for i1 in range(0, self.size+self.max_ch) : if i1 < self.size : self.pi_w[i1] = 1 # 適応度の計算前 else : self.pi_w[i1] = 0 # 未使用 # 遺伝子の決定 for i1 in range(0, self.size) : sw1 = 0 length = 0 while sw1 == 0 : # 遺伝子長の決定 if self.min_len < 0 : length = self.max_len else : length = int(random() * (self.max_len - self.min_len + 1) + self.min_len) if length > self.max_len : length = self.max_len self.len[i1] = length # 遺伝子の決定 for i2 in range(0, length) : sw2 = 0 while sw2 == 0 : lid = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l) if lid > self.allele_u : lid = self.allele_u self.ind[i1][i2] = lid # 重複遺伝子のチェック sw2 = 1 if self.dup_a == 0 : for i3 in range(0, i2) : if lid == self.ind[i1][i3] : sw2 = 0 break # 重複個体のチェック sw1 = 1 if self.dup_s == 0 : for i2 in range(0, i1) : if self.len[i1] == self.len[i2] : sw2 = 0 for i3 in range(0, self.len[i1]) : if self.ind[i1][i3] != self.ind[i2][i3] : sw2 = 1 break if sw2 == 0 : sw1 = 0 break #################################################### # 標準的な出力 # sw : 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負はファイル) # out_m : 出力方法 # =0 : すべての個体を出力 # =1 : 最大適応度の個体だけを出力 # gen : 現在の世代番号 # name : 出力ファイル名 #################################################### def Out_std(self, sw, out_m, gen, name) : k = 0 pr = -1 if sw >= 0 : pr = int(input(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ")) if pr != 0 : # 出力先の決定と評価値の出力 if pr > 0 : out = sys.stdout input("") else : now = datetime.today().time().isoformat() out = open(name, "a") out.write("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean) + " 時間 " + now + "\n") # 詳細出力 for i1 in range(0, self.size+self.max_ch) : if (self.pi_w[i1] > 1) and (out_m == 0 or (out_m == 1 and i1 == self.max_n)) : out.write(str(i1) + " allele") for i2 in range(0, self.len[i1]) : out.write(" " + str(self.ind[i1][i2])) out.write(" value " + str(self.pi[i1]) + "\n") if pr > 0 : k += 1 if k == pr : input("") k = 0 if pr < 0 : out.close() ################################################################### # 交叉(親のコピー) # method : =2 : 有性(2つの親から2つの子供)(default) # =1 : 1つの親から1つの子供 # pair : method=2 の時は親のペア数(default=max_ch/2) # method=1 の時は親の数(=子供の数) # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_copy(self, method = 2, pair = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータチェック if method != 1 : method = 2 if pair <= 0 : if method == 2 : pair = int(self.max_ch / 2) else : pair = self.max_ch else : if method == 2 and 2*pair > self.max_ch or method == 1 and pair > self.max_ch : print("***error 子供が多すぎる (C_copy)") # 実行 for i1 in range(0, pair) : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # コピー for i2 in range(0, method) : p = p2 if i2 == 0 : p = p1 k = self.Position(-1) self.len[k] = self.len[p] self.pi_w[k] = 1 for i3 in range(0, self.len[k]) : self.ind[k][i3] = self.ind[p][i3] ################################################################### # 交叉(多点交叉) # kosa : 交叉確率 # k_point : 交叉点の数(default=1) # (負の時は,1から-k_point間のランダム) # k_vr : =0 : 両親とも同じ位置で交叉(default) # =1 : 両親が異なる位置で交叉(遺伝子長は可変) # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_point(self, kosa, k_point = 1, k_vr = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) : mn = 0 # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a == 0 : print("***error 交叉方法が不適当 (C_point)") abs_p = abs(k_point) if abs_p == 0 or abs_p > self.max_len-1 or self.min_len > 0 and abs_p > self.min_len-1 : print("***error 交叉点の数が不適当 (C_point)") if k_vr > 0 and self.min_len < 0 : print("***error 遺伝子長は可変でなければならない (C_point)") # 交叉 num = k_point for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 交叉位置の数の決定 if k_point < 0 : num = int(random() * abs_p + 1) if num > abs_p : num = abs_p # 交叉位置の決定(点の後ろで交叉) for i2 in range(0, num) : # 親1の交叉位置 sw = 0 while sw == 0 : sw = 1 self.kou1[i2] = int(random() * (self.len[p1] - 1)) if self.kou1[i2] > self.len[p1]-2 : self.kou1[i2] = self.len[p1] - 2 if k_vr == 0 and self.kou1[i2] > self.len[p2]-2 : self.kou1[i2] = self.len[p2] - 2 for i3 in range(0, i2) : if self.kou1[i3] == self.kou1[i2] : sw = 0 break # 親2の交叉位置 if k_vr > 0 : sw = 0 while sw == 0 : sw = 1 self.kou2[i2] = int(random() * (self.len[p2] - 1)) if self.kou2[i2] > self.len[p2]-2 : self.kou2[i2] = self.len[p2] - 2 for i3 in range(0, i2) : if self.kou2[i3] == self.kou2[i2] : sw = 0 break # 交叉の実行 # 親1のt11からt12を子1のc1へコピー # 親2のt21からt22を子2のc2へコピー # 次は, # 親1のt11からt12を子2のc2へコピー # 親2のt21からt22を子1のc1へコピー # ・・・・・ c1 = 0 c2 = 0 t11 = 0 t21 = 0 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] for i2 in range(0, num+1) : # 次の交叉位置を求める if i2 == num : # 最後 t12 = self.len[p1] t22 = self.len[p2] else : # 親1 t12 = self.max_len for i3 in range(0, num) : if self.kou1[i3] >= 0 and self.kou1[i3] <= t12 : t12 = self.kou1[i3] mn = i3 self.kou1[mn] = -1 t12 += 1 # 親2 if k_vr == 0 : t22 = t12 else : t22 = self.max_len for i3 in range(0, num) : if self.kou2[i3] >= 0 and self.kou2[i3] <= t22 : t22 = self.kou2[i3] mn = i3 self.kou2[mn] = -1 t22 += 1 # 指定箇所のコピー for i3 in range(t11, t12) : if i2%2 == 0 : if c1 < self.max_len : self.ind[k1][c1] = self.ind[p1][i3] c1 += 1 else : if c2 < self.max_len : self.ind[k2][c2] = self.ind[p1][i3] c2 += 1 for i3 in range(t21, t22) : if i2%2 == 0 : if c2 < self.max_len : self.ind[k2][c2] = self.ind[p2][i3] c2 += 1 else : if c1 < self.max_len : self.ind[k1][c1] = self.ind[p2][i3] c1 += 1 # 交叉位置の移動 t11 = t12 t21 = t22 ################################################################### # 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, # 親1,0であれば親2の遺伝子を子1が受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_uniform(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a == 0 : print("***error 交叉方法が不適当 (C_uniform)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_uniform)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 for i2 in range(0, self.len[p1]) : if random() > 0.5 : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] else : self.ind[k1][i2] = self.ind[p2][i2] self.ind[k2][i2] = self.ind[p1][i2] ################################################################### # 交叉(平均化交叉.2つの親の平均値を受け継ぐ) # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_mean(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_mean)") # 交叉 for i1 in range(0, self.max_ch) : # 交叉しない場合 if random() > kosa : self.C_copy(1, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k = self.Position(-1) self.len[k] = self.len[p1] self.pi_w[k] = 1 # 交叉 for i2 in range(0, self.len[k]) : self.ind[k][i2] = int((self.ind[p1][i2] + self.ind[p2][i2]) / 2) ################################################################### # 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を # そのまま各子供が選択する.その位置にある親2(1)の遺伝 # 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 # ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 # 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り # 返し,残りの遺伝子については,子1(2)は,親2(1)の # 遺伝子をその順番通りに受け継ぐ) # 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 # * → → # 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_cycle(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_cycle)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_cycle)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 初期設定 for i2 in range(0, self.len[p1]) : self.kou1[i2] = 0 self.kou2[i2] = 0 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 sw = 0 while sw == 0 : sw = 1 p = int(random() * self.len[p1]) if p >= self.len[p1] : p = self.len[p1] - 1 if self.kou1[p] == 0 and self.kou2[p] == 0 : self.kou1[p] = 1 self.kou2[p] = 1 self.ind[k1][p] = self.ind[p1][p] self.ind[k2][p] = self.ind[p2][p] for i2 in range(0, self.len[p1]) : if self.ind[p2][p] == self.ind[p1][i2] : self.ind[k1][i2] = self.ind[p1][i2] self.kou1[i2] = 1 sw = 0 break sw = 1 for i2 in range(0, self.len[p2]) : if self.ind[p1][p] == self.ind[p2][i2] : self.ind[k2][i2] = self.ind[p2][i2] self.kou2[i2] = 1 sw = 0 break sw = 0 i2 = 0 i3 = 0 while sw == 0 : while sw == 0 and i2 < self.len[p1] : if self.kou1[i2] == 0 : sw = 1 else : i2 += 1 sw = 0 while sw == 0 and i3 < self.len[p2] : if self.kou2[i3] == 0 : sw = 1 else : i3 += 1 if i2 < self.len[p1] and i3 < self.len[p2] : self.ind[k1][i2] = self.ind[p2][i3] self.ind[k2][i3] = self.ind[p1][i2] sw = 0 i2 += 1 i3 += 1 else : sw = 1 ################################################################### # 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と # 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ # の2つの遺伝子の位置を交換する.この操作を,選択した点よ # り右にあるすべての遺伝子に対して実施する # 2 4 1 3 6 5 2 4 5 3 6 1 # * → → ・・・・・ # 3 2 5 4 1 6 3 2 1 4 5 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) #******************************************************************/ def C_part(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_part)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_part)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 p = int(random() * self.len[p1]) if p >= self.len[p1] : p = self.len[p1] - 1 for i2 in range(0, self.len[p1]) : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] for i2 in range(p, self.len[p1]) : sw = 0 lv = self.ind[k1][i2] for i3 in range(0, self.len[p1]) : if self.ind[k2][i2] == self.ind[k1][i3] : self.ind[k1][i2] = self.ind[k1][i3] self.ind[k1][i3] = lv sw = 1 break sw = 0 for i3 in range(0, self.len[p1]) : if lv == self.ind[k2][i3] : self.ind[k2][i3] = self.ind[k2][i2] self.ind[k2][i2] = lv sw = 1 break ################################################################### # 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の # 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 # の遺伝子を親2の遺伝子の出現順序に並べ替える. # 2 4 1 3 6 5 2 4 1 3 5 6 # * → # 3 2 5 4 1 6 3 2 5 4 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_seq(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_seq)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_seq)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 p = int(random() * (self.len[p1] - 1)) if p >= self.len[p1]-1 : p = self.len[p1] - 2 for i2 in range(0, p+1) : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] pp = 0 for i2 in range(p+1, self.len[p1]) : sw = 0 i3 = pp while i3 < self.len[p2] and sw == 0 : i4 = p + 1 while i4 < self.len[p1] and sw == 0 : if self.ind[p2][i3] == self.ind[p1][i4] : sw = 1 pp = i3 + 1 self.ind[k1][i2] = self.ind[p1][i4] i4 += 1 i3 += 1 pp = 0 for i2 in range(p+1, self.len[p2]) : sw = 0 i3 = pp while i3 < self.len[p1] and sw == 0 : i4 = p + 1 while i4 < self.len[p2] and sw == 0 : if self.ind[p1][i3] == self.ind[p2][i4] : sw = 1 pp = i3 + 1 self.ind[k2][i2] = self.ind[p2][i4] i4 += 1 i3 += 1 ################################################################### # 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の順序に従って,他の親の遺伝子 # を並べ替える # 2 4 1 3 6 5 2 4 1 3 6 5 # * * → # 3 2 5 4 1 6 4 2 5 3 1 6 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_useq(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair =int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_useq)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_useq)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 for i2 in range(0, self.len[p1]) : self.ind[k1][i2] = self.ind[p1][i2] self.ind[k2][i2] = self.ind[p2][i2] if random() < 0.5 : self.kou1[i2] = 0 else : self.kou1[i2] = 1 p = 0 for i2 in range(0, self.len[p1]) : if self.kou1[i2] > 0 : sw = 0 i3 = p while i3 < self.len[p2] and sw == 0 : i4 = 0 while i4 < self.len[p1] and sw == 0 : if self.ind[p2][i3] == self.ind[p1][i4] and self.kou1[i4] > 0 : sw = 1 p = i3 + 1 self.ind[k1][i2] = self.ind[p1][i4] i4 += 1 i3 += 1 p = 0 for i2 in range(0, self.len[p3]) : if self.kou1[i2] > 0 : sw = 0 i3 = p while i3 < self.len[p1] and sw == 0 : i4 = 0 while i4 < self.len[p2] and sw == 0 : if self.ind[p1][i3] == self.ind[p2][i4] and self.kou1[i4] > 0 : sw = 1 p = i3 + 1 self.ind[k2][i2] = self.ind[p2][i4] i4 += 1 i3 += 1 ################################################################### # 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 # 択された位置における遺伝子の位置に,他の親の同じ遺伝子を # 配置する.残りの遺伝子は,親と同じ順序に配置する. # 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 # * * → → # 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_upos(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : # 初期設定とデータのチェック pair = int(self.max_ch / 2) if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_upos)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_upos)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p2] # 交叉 for i2 in range(0, self.len[p1]) : self.kou1[i2] = 1 if random() < 0.5 : self.kou1[i2] = 1 if self.kou1[i2] > 0 : self.ind[k1][i2] = self.ind[p2][i2] self.ind[k2][i2] = self.ind[p1][i2] p = 0 for i2 in range(0, self.len[p1]) : sw = 0 for i3 in range(0, self.len[p1]) : if self.kou1[i3] > 0 and self.ind[p1][i2] == self.ind[k1][i3] : sw = 1 break if sw == 0 : for i3 in range(p, self.len[p1]) : if self.kou1[i3] == 0 : self.ind[k1][i3] = self.ind[p1][i2] p = i3 + 1 sw = 1 break p = 0 for i2 in range(0, self.len[p2]) : sw = 0 for i3 in range(0, self.len[p2]) : if self.kou1[i3] > 0 and self.ind[p2][i2] == self.ind[k2][i3] : sw = 1 break if sw == 0 : for i3 in range(p, self.len[p2]) : if self.kou1[i3] == 0 : self.ind[k2][i3] = self.ind[p2][i2] p = i3 + 1 sw = 1 break ################################################################### # 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は # 0~(max_len-1)である必要がある) # (0) エッジマップを作成する.エッジマップとは,2つの親 # を見て,ノードがどこに接続されているのかを表すもの # であり,例えば,2つの親が, # [A B C D E F] # [B D C A E F] # である場合は, # A : B F C E # B : A C D F # C : B D A # D : C E B # E : D F A # F : A E B # となる. # (1) 両親の2つの出発点の内1つで初期化する.ランダムま # たはステップ(4)の基準に従って選ぶ(現在のノード) # (2) エッジマップから,現在のノードを除く # (3) 現在のノードが接続先のノードを持っていたら,(4)に # 進む.さもなければ,(5)に進む # (4) 現在のノードが持っている接続先ノードの内,最も少な # い接続先ノードを持ったノードを選択し(同じ条件の場 # 合は,ランダム),それを現在のノードとし,(2)に進む # (5) 未接続のノードが残っていればランダムに選択し,(2)に # 戻る.さもなければ,終了する # kosa : 交叉確率 # k_method : 選択方法 # =-1 : ランダム(default) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # k_bias : α,または,method=2の場合は初期値(default=0) # k_step : β(default=1) ################################################################### def C_edge(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) : e = np.empty(2, np.int) k0 = 0 # 初期設定とデータのチェック pair = self.max_ch if self.dup_a != 0 : print("***error 交叉方法が不適当 (C_edge)") if self.min_len > 0 : print("***error 遺伝子長は固定長でなければならない (C_edge)") # 交叉 for i1 in range(0, pair) : # 交叉しない場合 if random() > kosa : self.C_copy(1, 1) # 交叉する場合 else : # 親の選択 p1 = self.Select(k_method, k_bias, k_step) p2 = p1 sw = 0 while sw == 0 : p2 = self.Select(k_method, k_bias, k_step) if p1 != p2 : sw = 1 # 遺伝子長 k = self.Position(-1) self.pi_w[k] = 1 self.len[k] = self.len[p1] # エッジマップの初期化 for i2 in range(0, self.len[k]) : self.edge[i2][0] = 0 for i3 in range(1, 5) : self.edge[i2][i3] = -1 # 交叉 # エッジマップの作成 for i2 in range(0, self.len[k]) : sw = 0 for i3 in range(0, self.len[k]) : if i2 == self.ind[p1][i3] : sw = 1 if i3 == 0 : e[0] = self.ind[p1][self.len[k]-1] e[1] = self.ind[p1][1] else : if i3 == self.len[k]-1 : e[0] = self.ind[p1][i3-1] e[1] = self.ind[p1][0] else : e[0] = self.ind[p1][i3-1] e[1] = self.ind[p1][i3+1] for i4 in range(0, 2) : self.edge[i2][0] += 1 self.edge[i2][self.edge[i2][0]] = e[i4] break sw = 0 for i3 in range(0, self.len[k]) : if i2 == self.ind[p2][i3] : sw = 1 if i3 == 0 : e[0] = self.ind[p2][self.len[k]-1] e[1] = self.ind[p2][1] else : if i3 == self.len[k]-1 : e[0] = self.ind[p2][i3-1] e[1] = self.ind[p2][0] else : e[0] = self.ind[p2][i3-1] e[1] = self.ind[p2][i3+1] for i4 in range(0, 2) : sw = 1 for i5 in range(1, self.edge[i2][0]+1) : if self.edge[i2][i5] == e[i4] : sw = 2 break if sw == 1 : self.edge[i2][0] += 1 self.edge[i2][self.edge[i2][0]] = e[i4] break # 交叉の実行 # 出発点の決定 k1 = self.ind[p1][0] k2 = self.ind[p2][0] if self.edge[k1][0] == self.edge[k2][0] : kk = k1 if random() > 0.5 : kk = k2 else : kk = k2 if self.edge[k1][0] < self.edge[k2][0] : kk = k2 self.ind[k][0] = kk p = 1 while p < self.len[k] : # ノードの除去 for i2 in range(0, self.len[k]) : sw = 0 if self.edge[i2][0] > 0 : for i3 in range(1, 5) : if self.edge[i2][i3] == kk : sw = 1 self.edge[i2][i3] = -1 self.edge[i2][0] -= 1 break # 次の現在ノードの選択 min = 10 num = 0 for i2 in range(1, 5) : if self.edge[kk][i2] >= 0 : k1 = self.edge[kk][i2] if self.edge[k1][0] >= 0 and self.edge[k1][0] < min : num = 1 min = self.edge[k1][0] k0 = k1 else : if self.edge[k1][0] == min : num += 1 if num > 1 : k1 = int(random() * num) + 1 if k1 > num : k1 = num k2 = 0 k0 = -1 i2 = 1 while i2 <= 4 and k0 < 0 : if self.edge[kk][i2] >= 0 : if self.edge[self.edge[kk][i2]][0] == min : k2 += 1 if k1 == k2 : k0 = self.edge[kk][i2] i2 += 1 else : if num <= 0 : num = 0 for i2 in range(0, self.len[k]) : if i2 != kk and self.edge[i2][0] >= 0 : num += 1 if num <= 0 : print("***error invalid data (C_edge)") else : k1 = int(random() * num) + 1 if k1 > num : k1 = num k2 = 0 k0 = -1 i2 = 0 while i2 < self.len[k] and k0 < 0 : if i2 != kk and self.edge[i2][0] >= 0 : k2 += 1 if k1 == k2 : k0 = i2 i2 += 1 self.edge[kk][0] = -1 self.ind[k][p] = k0 kk = k0 p += 1 ############################################################## # 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に # 同じ遺伝子のグループがない限り実行されない.たとえば # ***abcd** # *cdab**** # のような両親の時実行され,以下の4つの子供が生成され # る) # ***cdab** # *abcd**** # ***badc** # *dcba**** # 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 # 供が生成される可能性があるので,子供の数としてこの値 # 以上のデータを入力しておく必要がある. # kosa : 交叉確率 # count : 1つのペアーに対する交差回数(default=10) ############################################################## def C_sub(self, kosa, count = 10) : t22 = 0 # 初期設定とデータのチェック if (4*count*self.size*(self.size-1)) > self.max_ch : print("***error 子供が多すぎる (C_sub)") # 交叉 for i1 in range(0, self.size-1) : # 親1 p1 = self.Position(i1) if p1 >= 0 : for i2 in range(i1, self.size) : # 親2 p2 = self.Position(i2) if p2 >= 0 : # 交叉しない場合 if random() > kosa : self.C_copy(2, 1) # 交叉する場合 else : # 交叉回数の制御 for i3 in range(0, count) : # 交叉位置の決定(点の後ろで交叉) # 親1の交叉位置 t11 = int(random() * self.len[p1]) if t11 > (self.len[p1]-1) : t11 = self.len[p1] - 1 sw = 0 while sw == 0 : t12 = int(random() * self.len[p1]) if t12 > (self.len[p1]-1) : t12 = self.len[p1] - 1 if t12 != t11 : sw = 1 if t11 > t12 : k1 = t11 t11 = t12 t12 = k1 # 親2の交叉位置 sw = 0 t21 = -1 i4 = 0 while i4 < self.len[p2] and t21 < 0 : i5 = t11 while i5 <= t12 and t21 < 0 : if self.ind[p2][i4] == self.ind[p1][i5] : t21 = i4 i5 += 1 i4 += 1 if t21 >= 0 : t22 = t21 + t12 - t11 if t22 < self.len[p2] : sw = 1 i4 = t21 + 1 while i4 <= t22 and sw > 0 : sw = 0 i5 = t11 while i5 <= t12 and sw == 0 : if self.ind[p2][i4] == self.ind[p1][i5] : sw = 1 i5 += 1 i4 += 1 # 交叉の実行 if sw > 0 : k1 = self.Position(-1) self.pi_w[k1] = 1 self.len[k1] = self.len[p1] k2 = self.Position(-1) self.pi_w[k2] = 1 self.len[k2] = self.len[p1] k3 = self.Position(-1) self.pi_w[k3] = 1 self.len[k3] = self.len[p2] k4 = self.Position(-1) self.pi_w[k4] = 1 self.len[k4] = self.len[p2] for i4 in range(0, t11) : self.ind[k1][i4] = self.ind[p1][i4] self.ind[k2][i4] = self.ind[p1][i4] for i4 in range(t11, t12+1) : self.ind[k1][i4] = self.ind[p2][t21+i4-t11] self.ind[k2][i4] = self.ind[p2][t22-i4+t11] for i4 in range(t12+1, self.len[p1]) : self.ind[k1][i4] = self.ind[p1][i4] self.ind[k2][i4] = self.ind[p1][i4] for i4 in range(0, t21) : self.ind[k3][i4] = self.ind[p2][i4] self.ind[k4][i4] = self.ind[p2][i4] for i4 in range(t21, t22+1) : self.ind[k3][i4] = self.ind[p1][t11+i4-t21] self.ind[k4][i4] = self.ind[p1][t12-i4+t21] for i4 in range(t22+1, self.len[p2]) : self.ind[k3][i4] = self.ind[p2][i4] self.ind[k4][i4] = self.ind[p2][i4] ####################################### # 突然変異(対立遺伝子との置き換え) # pr : 突然変異率 ####################################### def M_alle(self, pr) : # データのチェックと初期設定 if self.dup_a == 0 : print("***error 突然変異方法が不適当 (M_alle)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : for i2 in range(0, self.len[i1]) : if random() <= pr : lid = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l) if lid > self.allele_u : lid = self.allele_u if lid != self.ind[i1][i2] : self.ind[i1][i2] = lid ###################################################################### # 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に # 移動する) # pr : 突然変異率 ###################################################################### def M_move(self, pr) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 位置の決定 # p1 p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 # p2 p2 = p1 sw = 0 while sw == 0 : p2 = int(random() * self.len[i1]) if p2 >= self.len[i1] : p2 = self.len[i1] - 1 if p2 != p1 : sw = 1 # 実行 if p2 > p1 : ld = self.ind[i1][p2] for i2 in range(p2, p1, -1) : self.ind[i1][i2] = self.ind[i1][i2-1] self.ind[i1][p1] = ld else : ld = self.ind[i1][p2] for i2 in range(p2, p1-1) : self.ind[i1][i2] = self.ind[i1][i2+1] self.ind[i1][p1-1] = ld ######################################################## # 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ######################################################## def M_inv(self, pr, wd = 0) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間の決定 if wd == 0 : p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 sw = 0 p2 = p1 while sw == 0 : p2 = int(random() * self.len[i1]) if p2 >= self.len[i1] : p2 = self.len[i1] - 1 if p2 != p1 : sw = 1 if p1 > p2 : p = p1 p1 = p2 p2 = p else : p1 = self.len[i1] while p1 > self.len[i1]-2 : p1 = int(random() * self.len[i1]) p2 = p1 + wd - 1 if p2 >= self.len[i1] : p2 = self.len[i1] - 1 # 実行 sw = 0 while sw == 0 : lid = self.ind[i1][p1] self.ind[i1][p1] = self.ind[i1][p2] self.ind[i1][p2] = lid p1 += 1 p2 -= 1 if p1 >= p2 : sw = 1 ###################################################################### # 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_scram(self, pr, wd = 0) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間の決定 if wd == 0 : p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 sw = 0 p2 = p1 while sw == 0 : p2 = int(random() * self.len[i1]) if p2 >= self.len[i1] : p2 = self.len[i1] - 1 if p2 != p1 : sw = 1 if p1 > p2 : p = p1 p1 = p2 p2 = p else : p1 = self.len[i1] while p1 > self.len[i1]-2 : p1 = int(random() * self.len[i1]) p2 = p1 + wd - 1 if p2 >= self.len[i1] : p2 = self.len[i1] - 1 # 実行 for i2 in range(p1, p2+1) : p = int(random() * (p2 - p1 + 1) + p1) if p > p2 : p = p2 ld = self.ind[i1][i2] self.ind[i1][i2] = self.ind[i1][p] self.ind[i1][p] = ld ###################################################################### # 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし # 重複部分はそのままとする) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ###################################################################### def M_chg(self, pr, wd = 0) : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間等の決定([p1,p2]と[p3,p4]の入れ替え) # p1 p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 # p3 sw = 0 p3 = p1 while sw == 0 : p3 = int(random() * self.len[i1]) if p3 >= self.len[i1] : p3 = self.len[i1] - 1 if p3 != p1 : sw = 1 # 小さい方をp1,p2にする if p1 > p3 : p = p1 p1 = p3 p3 = p # p4, p2 p4 = p1 + wd - 1 if wd == 0 : p4 = int(random() * (self.len[i1] - p3)) + p3 if p4 >= self.len[i1] : p4 = self.len[i1] - 1 p2 = p1 + (p4 - p3) # 重複部分のチェック if p2 >= p3 : p = p3 - 1 p3 = p2 + 1 p2 = p p4 = p3 + (p2 - p1) # 実行 p = p3 for i2 in range(p1, p2+1) : ld = self.ind[i1][i2] self.ind[i1][i2] = self.ind[i1][p] self.ind[i1][p] = ld p += 1 ###################################################################### # 突然変異(重複.2点間の遺伝子を他の位置にコピーする # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(deafult) ###################################################################### def M_dup(self, pr, wd = 0) : # データのチェック if self.dup_a == 0 : print("***error 突然変異方法が不適当 (M_dup)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 区間の決定([p1,p2]を[p3,p4]にコピー) # p1 p1 = int(random() * self.len[i1]) if p1 >= self.len[i1] : p1 = self.len[i1] - 1 # p3 sw = 0 p3 = p1 while sw == 0 : p3 = int(random() * self.len[i1]) if p3 >= self.len[i1] : p3 = self.len[i1] - 1 if p3 != p1 : sw = 1 # 区間を決める p2 = p1 p4 = p1 if p3 > p1 : p4 = p3 + wd - 1 if wd == 0 : p4 = int(random() * (self.len[i1] - p3)) + p3 if p4 >= self.len[i1] : p4 = self.len[i1] - 1 p2 = p1 + (p4 - p3) else : p2 = p1 + wd - 1 if wd == 0 : p2 = int(random() * (self.len[i1] - p1)) + p1 if p2 >= self.len[i1] : p2 = self.len[i1] - 1 p4 = p3 + (p2 - p1) # 実行 p = p4 for i2 in range(p2, p1-1, -1) : self.ind[i1][p] = self.ind[i1][i2] p -= 1 ###################################################### # 突然変異(摂動.値をある量だけ変化させる) # pr : 突然変異率 # method : =0 : 正規分布(default) # =1 : 一様分布 # m : 平均または一様分布の下限(default=0.0) # s : 標準偏差または一様分布の上限(default=1.0) ###################################################### def M_per(self, pr, method = 0, m = 0.0, s = 1.0) : wd = 0.0 # データのチェックと初期設定 if self.dup_a == 0 : print("***error 突然変異方法が不適当 (M_per)") if method > 0 : wd = s - m # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : for i2 in range(0, self.len[i1]) : if random() <= pr : if method == 0 : w = normalvariate(m, s) else : w = random() * wd if random() < 0.5 : w = -w x1 = float(self.ind[i1][i2]) + w if x1 > self.allele_u : x1 = self.allele_u else : if x1 < self.allele_l : x1 = self.allele_l self.ind[i1][i2] = int(x1) ############################################## # 突然変異(挿入.ある長さの遺伝子を挿入する) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ############################################## def M_ins(self, pr, wd = 0) : # データのチェック if self.dup_a == 0 or self.min_len < 0 : print("***error 突然変異方法が不適当 (M_ins)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 挿入位置の決定 p = int(random() * (self.len[i1] + 1)) if p > self.len[i1] : p = self.len[i1] # 挿入する遺伝子長の決定 l = wd if wd == 0 : l = int(random() * (self.max_len - self.len[i1] + 1)) if l > self.max_len-self.len[i1] : l = self.max_len - self.len[i1] else : if l <= 0 : l = 1 # 実行 # 挿入場所の確保 if p < self.len[i1] : for i2 in range(self.len[i1]+l-1, p-1, -1) : self.ind[i1][i2] = self.ind[i1][i2-l] # 挿入場所の遺伝子の決定 for i2 in range(p, p+l) : ld = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l) if ld > self.allele_u : ld = self.allele_u self.ind[i1][i2] = ld self.len[i1] += l ############################################## # 突然変異(削除.ある長さの遺伝子を削除する) # pr : 突然変異率 # wd : >0 : 幅を固定 # =0 : 幅をランダム(default) ############################################## def M_del(self, pr, wd = 0) : # データのチェック if self.dup_a == 0 or self.min_len < 0 : print("***error 突然変異方法が不適当 (M_del)") # 実行 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 and random() <= pr : # 削除位置の決定 p = int(random() * self.len[i1]) if p >= self.len[i1] : p = self.len[i1] - 1 # 削除する遺伝子長の決定 max = self.len[i1] - p if self.len[i1]-self.min_len < self.len[i1]-p : max = self.len[i1] - self.min_len l = wd if wd == 0 : l = int(random() * max + 1) if l > max : l = max # 実行 for i2 in range(0, self.len[i1]-p-l) : self.ind[i1][p+i2] = self.ind[i1][p+i2+l] self.len[i1] -= l ###################################################################### # 淘汰(エリート・ルーレット選択) # elite : エリートで残す個体数(default=0) # s_method : ルーレット板の作成方法(default=1) # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 # s_bias : α,または,method=2の場合は初期値(default=0) # s_step : β(default=1) ###################################################################### def S_roul(self, elite = 0, s_method = 1, s_bias = 0.0, s_step = 1.0) : count = 0 k = 0 n = 0 # 値のチェックと初期設定 if s_method != 0 and s_method != 2 : s_method = 1 if elite > self.size : print("***error エリートで残す数が多すぎる (S_roul)") if s_method == 2 and s_step <= 0.0 : s_step = 1.0 for i1 in range(0, self.size+self.max_ch) : self.s_w[i1] = 0 # 重複個体を削除 if self.dup_s == 0 : for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 0 : for i2 in range(i1+1, self.size+self.max_ch) : if self.pi_w[i2] > 0 and self.len[i1] == self.len[i2] : sw = 0 for i3 in range(0, self.len[i1]) : if self.ind[i1][i3] != self.ind[i2][i3] : sw = 1 break if sw == 0 : self.pi_w[i2] = 0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 : n += 1 if n < 0 or self.dup_s == 0 and n < self.size : print("***error 残す個体がない (S_roul)") # 淘汰して残す個体を選ぶ # エリートの選択 sw = 0 while k < elite and k < n and sw == 0 : max = -1 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] > 1 and self.s_w[i1] == 0 : if max < 0 or self.pi[i1] > self.pi[max] : max = i1 if max < 0 : sw = 1 else : self.s_w[max] = 1 k += 1 # ルーレット選択 while count < self.size+self.max_ch and k < self.size : p = self.Select(s_method, s_bias, s_step) if self.dup_s == 0 and self.s_w[p] > 0 : count += 1 else : count = 0 self.s_w[p] += 1 k += 1 # 選択に失敗した場合の処理 if self.dup_s == 0 and k < self.size : i1 = 0 while i1 < self.size+self.max_ch and k < self.size : if self.pi_w[i1] > 1 and self.s_w[i1] == 0 : self.s_w[i1] = 1 k += 1 i1 += 1 # 複数回選択されたものの処理 for i1 in range(0, self.size+self.max_ch) : if self.s_w[i1] == 0 : self.pi_w[i1] = 0 for i1 in range(0, self.size+self.max_ch) : if self.s_w[i1] > 0 : if self.s_w[i1] > 1 : for i2 in range(2, self.s_w[i1]+1) : k = self.Position(-1) self.len[k] = self.len[i1] self.pi_w[k] = 2 self.pi[k] = self.pi[i1] for i3 in range(0, self.len[i1]) : self.ind[k][i3] = self.ind[i1][i3] ####################### # クラスFunctionの定義 ####################### class Function ( Species ) : ###################################### # コンストラクタ # name1 : Species定義ファイル名 # name2 : Function定義ファイル名 ###################################### def __init__(self, name1, name2) : Species.__init__(self, name1) # 親のコンストラクタ # 基本データの入力 inn = open(name2, "r") s = inn.readline().split() self.out_lvl = int(s[1]) # 出力レベル # =0 : 最終出力だけ # n>0 : n世代毎に出力(負の時はファイル) self.out_m = int(s[3]) # 出力方法 # =0 : すべてを出力 # =1 : 最大適応度の個体だけを出力 s = inn.readline().split() self.o_file = s[1] # 出力ファイル名 self.out_d = int(s[3]) # 表示間隔 s = inn.readline().split() self.kosa_m = int(s[1]) # 交叉方法 # =-1 : 交叉を使用しない # =0 : 親のコピー # =1 : 多点交叉 # =2 : 一様交叉 # =3 : 平均化交叉 self.kosa = float(s[3]) # 交叉確率 self.k_point = int(s[5]) # 交差点の数(負の時は,1から-k_point間のランダム) self.k_vr = int(s[7]) # =0 : 両親とも同じ位置で交叉 # =1 : 両親が異なる位置で交叉(遺伝子長は可変) self.k_method = int(s[9]) # 交叉の時の親の選択方法 # =-1 : ランダム # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 self.k_bias = float(s[11]) # α,または,method=2の場合は初期値 self.k_step = float(s[13]) # β s = inn.readline().split() self.mute_m = int(s[1]) # 突然変異方法 # =-1 : 突然変異を使用しない # =0 : 対立遺伝子への置換 # =1 : 移動 # =2 : 逆位 # =3 : スクランブル # =4 : 転座 # =5 : 重複 # =6 : 摂動 self.mute = float(s[3]) # 突然変異率 self.wd = int(s[5]) # 突然変異に使用する部分遺伝子長 self.m_mean = float(s[7]) # 摂動の平均値 self.m_std = float(s[9]) # 摂動の標準偏差 s = inn.readline().split() self.elite = int(s[1]) # エリート選択で残す数 self.s_method = int(s[3]) # ルーレット板の作成方法 # =0 : 適応度をそのまま使用 # =1 : 最小値からの差(ただし,α以下の場合はα) # =2 : 評価値に順位をつけ,減少率βで線形化 self.s_bias = float(s[5]) # α,または,s_method=2の場合は初期値 self.s_step = float(s[7]) # β s = inn.readline().split() self.max_gen = int(s[1]) # 最大世代交代数 self.cv = 1.0 / (pow(2.0, float(self.max_len)) - 1.0) # 2進数を10進数の変換する係数 inn.close() ############### # 全体の制御 ############### def Control(self) : gen = 1 # 初期集団の発生 self.Init_std() # 評価 self.Adap() # 出力 print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean)) if abs(self.out_lvl) > 0 : self.Output(gen) # 世代交代 for gen in range(2, self.max_gen+1) : # 交叉 if self.kosa_m == 0 : C_copy() # 親のコピー elif self.kosa_m == 1 : self.C_point(self.kosa, self.k_point) # 多点交叉 elif self.kosa_m == 2 : self.C_uniform(self.kosa) # 一様交叉 elif self.kosa_m == 3 : self.C_mean(self.kosa) # 平均化交叉 # 突然変異 if self.mute_m == 0 : self.M_alle(self.mute) # 対立遺伝子への置換 elif self.mute_m == 1 : self.M_move(self.mute) # 移動 elif self.mute_m == 2 : self.M_inv(self.mute, self.wd) # 逆位 elif self.mute_m == 3 : self.M_scram(self.mute, self.wd) # スクランブル elif self.mute_m == 4 : self.M_chg(self.mute, self.wd) # 転座 elif self.mute_m == 5 : self.M_dup(self.mute, self.wd) # 重複 elif self.mute_m == 6 : self.M_per(self.mute, self.wd, self.m_mean, self.m_std) # 摂動 # 適応度 self.Adap() # 淘汰 self.S_roul(self.elite) # 出力 if gen%self.out_d == 0 : print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean)) if abs(self.out_lvl) > 0 : if gen%abs(self.out_lvl) == 0 : self.Output(gen) gen -= 1 k1 = self.out_m self.out_m = 0 print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean)) self.Output(gen) self.out_m = k1 ################ # 適応度の計算 ################ def Adap(self) : n = 0 self.max = 0.0 self.max_n = -1 self.mean = 0.0 for i1 in range(0, self.size+self.max_ch) : if self.pi_w[i1] == 1 : x = 0.0 y = 0.0 for i2 in range(self.len[i1]-1, -1, -1) : if self.ind[i1][i2] > 0 : x += pow(2.0, y) y += 1.0 x *= self.cv self.pi[i1] = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x+50.0) self.pi_w[i1] = 2 if self.pi_w[i1] > 0 : self.mean += self.pi[i1] n += 1 if self.max_n < 0 or self.pi[i1] > self.max : self.max = self.pi[i1] self.max_n = i1 self.mean /= n ############################# # 結果の出力 # gen : 現在の世代番号 ############################# def Output(self, gen) : k = 0 pr = -1 if self.out_lvl >= 0 : print(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ", end=" ") pr = int(input()) if pr != 0 : # 出力先の決定と評価値の出力 if pr > 0 : out = sys.stdout input("") else : now = datetime.today().time().isoformat() out = open(self.o_file, "a") out.write("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean) + " 時間 " + now + "\n") # 詳細出力 for i1 in range(0, self.size+self.max_ch) : if (self.pi_w[i1] > 1) and (self.out_m == 0 or (self.out_m == 1 and i1 == self.max_n)) : out.write(str(i1) + " allele") for i2 in range(0, self.len[i1]) : out.write(" " + str(self.ind[i1][i2])) x = 0.0 y = 0.0 for i2 in range(self.len[i1]-1, -1, -1) : if self.ind[i1][i2] > 0 : x += pow(2.0, y) y += 1.0 x *= self.cv out.write(" x " + str(x) + " y " + str(self.pi[i1]) + "\n") if pr > 0 : k += 1 if k == pr : input("") k = 0 if pr < 0 : out.close() # 入力ミス if len(sys.argv) <= 1 : print("***error ファイル名を入力して下さい") # 入力OK else : # データの数と入力データファイル名の入力 inn = open(sys.argv[1], "r") ss = inn.readline() n = int(ss) # データの数 i_file1 = [] i_file2 = [] for i1 in range(0, n) : s = inn.readline().split() i_file1.append(s[0]) i_file2.append(s[1]) inn.close() # 実行(乱数の初期値を変える) for i1 in range(0, n) : print("\n+++++ケース " + str(i1+1) + "+++++") seed(1000 * i1 + 1234567); fn = Function(i_file1[i1], i_file2[i1]) fn.Control() """ ------------------ケーススタディデータ(data_cf.txt)------ 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt ------------------Species記述データ(data1_f.txt)--------- 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 ------------------Function記述データ(data2_f.txt)-------- 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 """
/***********************************/ /* 遺伝的アルゴリズムによるTSPの解 */ /* coded by Y.Suganuma */ /***********************************/ using System; using System.IO; /***********************/ /* クラスSpeciesの定義 */ /***********************/ class Species { protected double max; // 最大適応度 protected double mean; // 平均適応度 protected double [] pi; // 適応度 protected double [] ro; // ルーレット板 protected int allele_u; // 対立遺伝子上限 protected int allele_l; // 対立遺伝子下限 protected int size; // 個体総数 protected int max_ch; // 子供の数の最大値 protected int max_len; // 最大遺伝子長 protected int min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) protected int max_n; // 最大適応度の個体番号 protected int dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す protected int dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す protected int [][] ind; // 集団(個体の集まり) protected int [] len; // 各個体の遺伝子長 protected int [] kou1; // 交叉・突然変異用作業場所1 protected int [] kou2; // 交叉・突然変異用作業場所2 protected int [] s_w; // 淘汰用指標(選択された回数) protected int [][] edge; // エッジ組み替え交叉用ワークエリア protected byte [] pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) protected Random rn; // 乱数 /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ double norm_d(double m, double s) { double x = 0.0; for (int i1 = 0; i1 < 12; i1++) x += rn.NextDouble(); x = s * (x - 6.0) + m; return x; } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ int Position(int n) { int i1, k = -1, sw = 0; // // 空いている場所を探す // if (n < 0) { for (i1 = 0; i1 < size+max_ch && k < 0; i1++) { if (pi_w[i1] == 0) k = i1; } if (k < 0) { Console.WriteLine("***error 空いている場所がない --Position--"); Environment.Exit(1); } } // // n番目の親(pi_w[i]=2)を捜す // else { for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] == 2) { k++; if (k == n) { sw = 1; k = i1; } } } } return k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値 */ /* step : β */ /* return : 個体番号 */ /*******************************************************************/ int Select(int method, double bias, double step) { double sum = 0.0, x; int i1, k, min, n, sw; // ルーレット板の用意 switch (method) { // ランダム case -1: n = 0; 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; } break; // 評価値をそのまま利用 case 0: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += pi[i1]; n++; } } if (Math.Abs(sum) > 1.0e-10) { sum = 1.0 / Math.Abs(sum); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = pi[i1] * sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 最小値からの差 case 1: min = -1; n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { n++; if (min < 0 || pi[i1] < pi[min]) min = i1; } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = pi[i1] - pi[min]; if (ro[i1] < bias) ro[i1] = bias; sum += ro[i1]; } } if (sum > 1.0e-10) { sum = 1.0 / sum; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 線形化 case 2: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = -1.0; n++; } else ro[i1] = 1.0; } sw = 0; sum = bias; while (sw == 0) { min = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (ro[i1] < 0.0 && (min < 0 || pi[i1] < pi[min])) min = i1; } if (min < 0) sw = 1; else { ro[min] = sum; sum += step; } } sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } break; } 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; } /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ public Species (String name, int seed) { string[] lines = File.ReadAllLines(name); char[] charSep = new char[] {' '}; // // データの入力 // // 1行目 string[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); allele_u = int.Parse(str[1]); allele_l = int.Parse(str[3]); // 2行目 str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); max_len = int.Parse(str[1]); min_len = int.Parse(str[3]); // 3行目 str = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries); dup_a = int.Parse(str[1]); dup_s = int.Parse(str[3]); // 4行目 str = lines[3].Split(charSep, StringSplitOptions.RemoveEmptyEntries); size = int.Parse(str[1]); max_ch = int.Parse(str[3]); // // データのチェック // if (size <= 0) { Console.WriteLine("***error 個体総数≦0 (Constructor)"); Environment.Exit(1); } if (max_ch < 0) { Console.WriteLine("***error 子供の数<0 (Constructor)"); Environment.Exit(1); } if (max_len <= 0 || min_len == 0) { Console.WriteLine("***error 遺伝子長≦0 (Constructor)"); Environment.Exit(1); } if (max_len < min_len) { Console.WriteLine("***error 最大遺伝子長<最小遺伝子長 (Constructor)"); Environment.Exit(1); } if (allele_u <= allele_l) { Console.WriteLine("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)"); Environment.Exit(1); } int kind = allele_u - allele_l + 1; if (dup_a == 0 && max_len > kind) { Console.WriteLine("***error 遺伝子の重複を防ぐことはできない (Constructor)"); Environment.Exit(1); } // // 領域の確保 // int num = size + max_ch; ind = new int [num][]; for (int i1 = 0; i1 < num; i1++) ind[i1] = new int [max_len]; edge = new int [max_len][]; for (int i1 = 0; i1 < max_len; i1++) edge[i1] = new int [5]; pi = new double [num]; ro = new double [num]; len = new int [num]; kou1 = new int [max_len]; kou2 = new int [max_len]; s_w = new int [num]; pi_w = new byte [num]; // // 乱数の初期設定 // rn = new Random(seed); } /********************/ /* 標準的な初期設定 */ /********************/ protected void Init_std() { int i1, i2, i3, length, lid, 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) { // 遺伝子長の決定 if (min_len < 0) length = max_len; else { length = (int)(rn.NextDouble() * (max_len - min_len + 1) + min_len); if (length > max_len) length = max_len; } len[i1] = length; // 遺伝子の決定 for (i2 = 0; i2 < length; i2++) { sw2 = 0; while (sw2 == 0) { lid = (int)(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; ind[i1][i2] = lid; // 重複遺伝子のチェック sw2 = 1; if (dup_a == 0) { for (i3 = 0; i3 < i2 && sw2 > 0; i3++) { if (lid == ind[i1][i3]) sw2 = 0; } } } } // 重複個体のチェック sw1 = 1; if (dup_s == 0) { for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { if (len[i1] == len[i2]) { sw2 = 0; for (i3 = 0; i3 < len[i1] && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ void Out_std(int sw, int out_m, int gen, String name) { int pr = -1; if (sw >= 0) { Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = int.Parse(Console.ReadLine()); } if (pr != 0) { StreamWriter OUT = new StreamWriter(name, true); // 出力先の決定と評価値の出力 if (pr < 0) { DateTime now = DateTime.Now; // 現在時刻の獲得 OUT.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 詳細出力 int k = 0; for (int i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { if (pr < 0) { OUT.Write(i1 + " allele"); for (int i2 = 0; i2 < len[i1]; i2++) OUT.Write(" " + ind[i1][i2]); OUT.WriteLine(" value " + pi[i1]); } else { Console.Write(i1 + " allele"); for (int i2 = 0; i2 < len[i1]; i2++) Console.Write(" " + ind[i1][i2]); Console.WriteLine(" value " + pi[i1]); } if (pr > 0) { k++; if (k == pr) { Console.ReadLine(); k = 0; } } } } OUT.Close(); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数 */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_copy(int method, int pair, int k_method, double k_bias, double k_step) { int i1, i2, i3, k, p, p1, p2 = 0, sw; // // 初期設定とデータチェック // if (method != 1) method = 2; if (pair <= 0) pair = (method==2) ? max_ch/2 : max_ch; else { if (method == 2 && 2*pair > max_ch || method == 1 && pair > max_ch) { Console.WriteLine("***error 子供が多すぎる (C_copy)"); Environment.Exit(1); } } // // 実行 // for (i1 = 0; i1 < pair; i1++) { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // コピー for (i2 = 0; i2 < method; i2++) { p = (i2 == 0) ? p1 : p2; k = Position(-1); len[k] = len[p]; pi_w[k] = 1; for (i3 = 0; i3 < len[k]; i3++) ind[k][i3] = ind[p][i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数 */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉 */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_point(double kosa, int k_point, int k_vr, int k_method, double k_bias, double k_step) { int abs_p, c1, c2, i1, i2, i3, k1, k2, mn = 0, num, p1, p2 = 0, pair, sw, t11, t12, t21, t22; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a == 0) { Console.WriteLine("***error 交叉方法が不適当 (C_point)"); Environment.Exit(1); } abs_p = Math.Abs(k_point); if (abs_p == 0 || abs_p > max_len-1 || min_len > 0 && abs_p > min_len-1) { Console.WriteLine("***error 交叉点の数が不適当 (C_point)"); Environment.Exit(1); } if (k_vr > 0 && min_len < 0) { Console.WriteLine("***error 遺伝子長は可変でなければならない (C_point)"); Environment.Exit(1); } // // 交叉 // num = k_point; for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 交叉位置の数の決定 if (k_point < 0) { num = (int)(rn.NextDouble() * abs_p + 1); if (num > abs_p) num = abs_p; } // 交叉位置の決定(点の後ろで交叉) for (i2 = 0; i2 < num; i2++) { // 親1の交叉位置 sw = 0; while (sw == 0) { sw = 1; kou1[i2] = (int)(rn.NextDouble() * (len[p1] - 1)); if (kou1[i2] > len[p1]-2) kou1[i2] = len[p1] - 2; if (k_vr == 0 && kou1[i2] > len[p2]-2) kou1[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou1[i3] == kou1[i2]) sw = 0; } } // 親2の交叉位置 if (k_vr > 0) { sw = 0; while (sw == 0) { sw = 1; kou2[i2] = (int)(rn.NextDouble() * (len[p2] - 1)); if (kou2[i2] > len[p2]-2) kou2[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou2[i3] == kou2[i2]) sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ c1 = 0; c2 = 0; t11 = 0; t21 = 0; // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; for (i2 = 0; i2 < num+1; i2++ ) { // 次の交叉位置を求める if (i2 == num) { // 最後 t12 = len[p1]; t22 = len[p2]; } else { // 親1 t12 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou1[i3] >= 0 && kou1[i3] <= t12) { t12 = kou1[i3]; mn = i3; } } kou1[mn] = -1; t12++; // 親2 if (k_vr == 0) t22 = t12; else { t22 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou2[i3] >= 0 && kou2[i3] <= t22) { t22 = kou2[i3]; mn = i3; } } kou2[mn] = -1; t22++; } } // 指定箇所のコピー for (i3 = t11; i3 < t12; i3++) { if (i2%2 == 0) { if (c1 < max_len) { ind[k1][c1] = ind[p1][i3]; c1++; } } else { if (c2 < max_len) { ind[k2][c2] = ind[p1][i3]; c2++; } } } for (i3 = t21; i3 < t22; i3++) { if (i2%2 == 0) { if (c2 < max_len) { ind[k2][c2] = ind[p2][i3]; c2++; } } else { if (c1 < max_len) { ind[k1][c1] = ind[p2][i3]; c1++; } } } // 交叉位置の移動 t11 = t12; t21 = t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_uniform(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k1, k2, p1, p2 = 0, pair, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a == 0) { Console.WriteLine("***error 交叉方法が不適当 (C_uniform)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_uniform)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; 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]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_mean(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k, p1, p2 = 0, sw; // // 初期設定とデータのチェック // if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_mean)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < max_ch; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); len[k] = len[p1]; pi_w[k] = 1; // 交叉 for (i2 = 0; i2 < len[k]; i2++) ind[k][i2] = (ind[p1][i2] + ind[p2][i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_cycle(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_cycle)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_cycle)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 初期設定 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = 0; kou2[i2] = 0; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 sw = 0; while (sw == 0) { sw = 1; p = (int)(rn.NextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; if (kou1[p] == 0 && kou2[p] == 0) { kou1[p] = 1; kou2[p] = 1; ind[k1][p] = ind[p1][p]; ind[k2][p] = ind[p2][p]; for (i2 = 0; i2 < len[p1] && sw > 0; i2++) { if (ind[p2][p] == ind[p1][i2]) { ind[k1][i2] = ind[p1][i2]; kou1[i2] = 1; sw = 0; } } sw = 1; for (i2 = 0; i2 < len[p2] && sw > 0; i2++) { if (ind[p1][p] == ind[p2][i2]) { ind[k2][i2] = ind[p2][i2]; kou2[i2] = 1; sw = 0; } } } } sw = 0; i2 = 0; i3 = 0; while (sw == 0) { while (sw == 0 && i2 < len[p1]) { if (kou1[i2] == 0) sw = 1; else i2++; } sw = 0; while (sw == 0 && i3 < len[p2]) { if (kou2[i3] == 0) sw = 1; else i3++; } if (i2 < len[p1] && i3 < len[p2]) { ind[k1][i2] = ind[p2][i3]; ind[k2][i3] = ind[p1][i2]; sw = 0; i2++; i3++; } else sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_part(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, lv, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_part)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_part)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.NextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } for (i2 = p; i2 < len[p1]; i2++) { sw = 0; lv = ind[k1][i2]; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (ind[k2][i2] == ind[k1][i3]) { ind[k1][i2] = ind[k1][i3]; ind[k1][i3] = lv; sw = 1; } } sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (lv == ind[k2][i3]) { ind[k2][i3] = ind[k2][i2]; ind[k2][i2] = lv; sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_seq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, pp, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_seq)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_seq)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.NextDouble() * (len[p1] - 1)); if (p >= len[p1]-1) p = len[p1] - 2; for (i2 = 0; i2 <= p; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } pp = 0; for (i2 = p+1; i2 < len[p1]; i2++) { sw = 0; for (i3 = pp; i3 < len[p2] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4]) { sw = 1; pp = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } pp = 0; for (i2 = p+1; i2 < len[p2]; i2++) { sw = 0; for (i3 = pp; i3 < len[p1] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4]) { sw = 1; pp = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_useq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_useq)\n"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_useq)\n"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; kou1[i2] = (rn.NextDouble() < 0.5) ? 0 : 1; } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p2] && sw == 0; i3++) { for (i4 = 0; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p1] && sw == 0; i3++) { for (i4 = 0; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_upos(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_upos)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_upos)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = (rn.NextDouble() < 0.5) ? 0 : 1; if (kou1[i2] > 0) { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p1][i2] == ind[k1][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k1][i3] = ind[p1][i2]; p = i3 + 1; sw = 1; } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { sw = 0; for (i3 = 0; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p2][i2] == ind[k2][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k2][i3] = ind[p2][i2]; p = i3 + 1; sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_edge(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, i5, k, kk, k0 = 0, k1, k2, min, num, p, pair, p1, p2 = 0, sw; int[] e = new int [2]; // // 初期設定とデータのチェック // pair = max_ch; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_edge)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_edge)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); pi_w[k] = 1; len[k] = len[p1]; // エッジマップの初期化 for (i2 = 0; i2 < len[k]; i2++) { edge[i2][0] = 0; for (i3 = 1; i3 <= 4; i3++) edge[i2][i3] = -1; } // 交叉 // エッジマップの作成 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p1][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p1][len[k]-1]; e[1] = ind[p1][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p1][i3-1]; e[1] = ind[p1][0]; } else { e[0] = ind[p1][i3-1]; e[1] = ind[p1][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p2][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p2][len[k]-1]; e[1] = ind[p2][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p2][i3-1]; e[1] = ind[p2][0]; } else { e[0] = ind[p2][i3-1]; e[1] = ind[p2][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { sw = 1; for (i5 = 1; i5 <= edge[i2][0] && sw == 1; i5++) { if (edge[i2][i5] == e[i4]) sw = 2; } if (sw == 1) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } } } // 交叉の実行 // 出発点の決定 k1 = ind[p1][0]; k2 = ind[p2][0]; if (edge[k1][0] == edge[k2][0]) kk = (rn.NextDouble() > 0.5) ? k2 : k1; else kk = (edge[k1][0] < edge[k2][0]) ? k1 : k2; ind[k][0] = kk; p = 1; while (p < len[k]) { // ノードの除去 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; if (edge[i2][0] > 0) { for (i3 = 1; i3 <= 4 && sw == 0; i3++) { if (edge[i2][i3] == kk) { sw = 1; edge[i2][i3] = -1; edge[i2][0]--; } } } } // 次の現在ノードの選択 min = 10; num = 0; for (i2 = 1; i2 <= 4; i2++) { if (edge[kk][i2] >= 0) { k1 = edge[kk][i2]; if (edge[k1][0] >= 0 && edge[k1][0] < min) { num = 1; min = edge[k1][0]; k0 = k1; } else { if (edge[k1][0] == min) num++; } } } if (num > 1) { k1 = (int)(rn.NextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 1; i2 <= 4 && k0 < 0; i2++) { if (edge[kk][i2] >= 0) { if (edge[edge[kk][i2]][0] == min) { k2++; if (k1 == k2) k0 = edge[kk][i2]; } } } } else { if (num <= 0) { num = 0; for (i2 = 0; i2 < len[k]; i2++) { if (i2 != kk && edge[i2][0] >= 0) num++; } if (num <= 0) { Console.WriteLine("***error invalid data (C_edge)"); Environment.Exit(1); } else { k1 = (int)(rn.NextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 0; i2 < len[k] && k0 < 0; i2++) { if (i2 != kk && edge[i2][0] >= 0) { k2++; if (k1 == k2) k0 = i2; } } } } } edge[kk][0] = -1; ind[k][p] = k0; kk = k0; p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数 */ /*************************************************************/ protected void C_sub(double kosa, int count) { int i1, i2, i3, i4, i5, k1, k2, k3, k4, p1, p2, t11, t12 = 0, t21, t22 = 0, sw; // // 初期設定とデータのチェック // if ((4*count*size*(size-1)) > max_ch) { Console.WriteLine("***error 子供が多すぎる (C_sub)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < size-1; i1++) { // 親1 p1 = Position(i1); if (p1 >= 0) { for (i2 = i1; i2 < size; i2++) { // 親2 p2 = Position(i2); if (p2 >= 0) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 交叉回数の制御 for (i3 = 0; i3 < count; i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 t11 = (int)(rn.NextDouble() * len[p1]); if (t11 > (len[p1]-1)) t11 = len[p1] - 1; sw = 0; while (sw == 0) { t12 = (int)(rn.NextDouble() * len[p1]); if (t12 > (len[p1]-1)) t12 = len[p1] - 1; if (t12 != t11) sw = 1; } if (t11 > t12) { k1 = t11; t11 = t12; t12 = k1; } // 親2の交叉位置 sw = 0; t21 = -1; for (i4 = 0; i4 < len[p2] && t21 < 0; i4++) { for (i5 = t11; i5 <= t12 && t21 < 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) t21 = i4; } } if (t21 >= 0) { t22 = t21 + t12 - t11; if (t22 < len[p2]) { sw = 1; for (i4 = t21+1; i4 <= t22 && sw > 0; i4++) { sw = 0; for (i5 = t11; i5 <= t12 && sw == 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) sw = 1; } } } } // 交叉の実行 if (sw > 0) { k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p1]; k3 = Position(-1); pi_w[k3] = 1; len[k3] = len[p2]; k4 = Position(-1); pi_w[k4] = 1; len[k4] = len[p2]; for (i4 = 0; i4 < t11; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = t11; i4 <= t12; i4++) { ind[k1][i4] = ind[p2][t21+i4-t11]; ind[k2][i4] = ind[p2][t22-i4+t11]; } for (i4 = t12+1; i4 < len[p1]; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = 0; i4 < t21; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } for (i4 = t21; i4 <= t22; i4++) { ind[k3][i4] = ind[p1][t11+i4-t21]; ind[k4][i4] = ind[p1][t12-i4+t21]; } for (i4 = t22+1; i4 < len[p2]; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ protected void M_alle(double pr) { int i1, i2, lid; // // データのチェックと初期設定 // if (dup_a == 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_alle)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.NextDouble() <= pr) { lid = (int)(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; if (lid != ind[i1][i2]) ind[i1][i2] = lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ protected void M_move(double pr) { int i1, i2, ld, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 位置の決定 // // p1 p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p2 sw = 0; while (sw == 0) { p2 = (int)(rn.NextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } // // 実行 // if (p2 > p1) { ld = ind[i1][p2]; for (i2 = p2; i2 > p1; i2--) ind[i1][i2] = ind[i1][i2-1]; ind[i1][p1] = ld; } else { ld = ind[i1][p2]; for (i2 = p2; i2 < p1-1; i2++) ind[i1][i2] = ind[i1][i2+1]; ind[i1][p1-1] = ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /********************************************************/ protected void M_inv(double pr, int wd) { int i1, lid, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 区間の決定 // if (wd == 0) { p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.NextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.NextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } // // 実行 // sw = 0; while (sw == 0) { lid = ind[i1][p1]; ind[i1][p1] = ind[i1][p2]; ind[i1][p2] = lid; p1++; p2--; if (p1 >= p2) sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_scram(double pr, int wd) { int i1, i2, ld, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 区間の決定 // if (wd == 0) { p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.NextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.NextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } // // 実行 // for (i2 = p1; i2 <= p2; i2++) { p = (int)(rn.NextDouble() * (p2 - p1 + 1) + p1); if (p > p2) p = p2; ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_chg(double pr, int wd) { int i1, i2, ld, p, p1, p2, p3 = 0, p4, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 区間等の決定([p1,p2]と[p3,p4]の入れ替え) // // p1 p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.NextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 小さい方をp1,p2にする if (p1 > p3) { p = p1; p1 = p3; p3 = p; } // p4, p2 p4 = (wd == 0) ? (int)(rn.NextDouble() * (len[i1] - p3)) + p3 : p1 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); // 重複部分のチェック if (p2 >= p3) { p = p3 - 1; p3 = p2 + 1; p2 = p; p4 = p3 + (p2 - p1); } // // 実行 // p = p3; for (i2 = p1; i2 <= p2; i2++) { ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_dup(double pr, int wd) { int i1, i2, p, p1, p2, p3 = 0, p4, sw; // // データのチェック // if (dup_a == 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_dup)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.NextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 区間を決める if (p3 > p1) { p4 = (wd == 0) ? (int)(rn.NextDouble() * (len[i1] - p3)) + p3 : p3 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); } else { p2 = (wd == 0) ? (int)(rn.NextDouble() * (len[i1] - p1)) + p1 : p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; p4 = p3 + (p2 - p1); } // 実行 p = p4; for (i2 = p2; i2 >= p1; i2--) { ind[i1][p] = ind[i1][i2]; p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布 */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限 */ /* s : 標準偏差または一様分布の上限 */ /******************************************************/ protected void M_per(double pr, int method, double m, double s) { double w, wd = 0.0, x1; int i1, i2; // // データのチェックと初期設定 // if (dup_a == 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_per)"); Environment.Exit(1); } if (method > 0) wd = s - m; // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.NextDouble() <= pr) { if (method == 0) w = norm_d(m, s); else { w = rn.NextDouble() * wd; if (rn.NextDouble() < 0.5) w = -w; } x1 = (double)ind[i1][i2] + w; if (x1 > allele_u) x1 = allele_u; else { if (x1 < allele_l) x1 = allele_l; } ind[i1][i2] = (int)x1; } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_ins(double pr, int wd) { int i1, i2, l, ld, p; // // データのチェック // if (dup_a == 0 || min_len < 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_ins)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // 挿入位置の決定 p = (int)(rn.NextDouble() * (len[i1]+1)); if (p > len[i1]) p = len[i1]; // 挿入する遺伝子長の決定 l = (wd == 0) ? (int)(rn.NextDouble() * (max_len - len[i1] + 1)) : wd; if (l > max_len-len[i1]) l = max_len - len[i1]; else { if (l <= 0) l = 1; } // 実行 // 挿入場所の確保 if (p < len[i1]) { for (i2 = len[i1]+l-1; i2 >= p; i2--) ind[i1][i2] = ind[i1][i2-l]; } // 挿入場所の遺伝子の決定 for (i2 = p; i2 < p+l; i2++) { ld = (int)(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l); if (ld > allele_u) ld = allele_u; ind[i1][i2] = ld; } len[i1] += l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_del(double pr, int wd) { int i1, i2, l, max, p; // // データのチェック // if (dup_a == 0 || min_len < 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_del)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // 削除位置の決定 p = (int)(rn.NextDouble() * len[i1]); if (p >= len[i1]) p = len[i1] - 1; // 削除する遺伝子長の決定 max = (len[i1]-min_len < len[i1]-p) ? len[i1] - min_len : len[i1] - p; l = (wd == 0) ? (int)(rn.NextDouble() * max + 1) : wd; if (l > max) l = max; // 実行 for (i2 = 0; i2 < len[i1]-p-l; i2++) ind[i1][p+i2] = ind[i1][p+i2+l]; len[i1] -= l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ protected void S_roul(int elite, int s_method, double s_bias, double s_step) { int count = 0, i1, i2, i3, k = 0, max, n = 0, p, sw; // // 値のチェックと初期設定 // if (s_method != 0 && s_method != 2) s_method = 1; if (elite > size) { Console.WriteLine("***error エリートで残す数が多すぎる (S_roul)"); Environment.Exit(1); } if (s_method == 2 && s_step <= 0.0) s_step = 1.0; for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; // // 重複個体を削除 // if (dup_s == 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 && len[i1] == len[i2]) { sw = 0; for (i3 = 0; i3 < len[i1] && 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 || dup_s == 0 && n < size) { Console.WriteLine("***error 残す個体がない (S_roul)"); Environment.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++; } } // ルーレット選択 while (count < size+max_ch && k < size) { p = Select(s_method, s_bias, s_step); if (dup_s == 0 && s_w[p] > 0) count++; else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (dup_s == 0 && k < size) { for (i1 = 0; i1 < size+max_ch && k < size; 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(-1); len[k] = len[i1]; pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < len[i1]; i3++) ind[k][i3] = ind[i1][i3]; } } } } } } /*******************/ /* クラスTSPの定義 */ /*******************/ class TSP : Species { int max_gen; // 最大世代交代数 int kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 循環交叉 // =2 : 部分的交叉 // =3 : 順序交叉 // =4 : 一様順序交叉 // =5 : 一様位置交叉 // =6 : エッジ組み替え交叉 // =7 : サブツアー交叉 double kosa; // 交叉確率 int k_point; // 交差点の数(負の時は,1から-point間のランダム) int k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) int k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double k_bias; // α,または,method=2の場合は初期値 double k_step; // β int mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 移動 // =1 : 逆位 // =2 : スクランブル // =3 : 転座 double mute; // 突然変異率 int wd; // 突然変異に使用する部分遺伝子長 double m_mean; // 摂動の平均値 double m_std; // 摂動の標準偏差 int elite; // エリート選択で残す数 int s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double s_bias; // α,または,s_method=2の場合は初期値 double s_step; // β int out_d; // 表示間隔 int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) int out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 String o_file; // 出力ファイル名 int n_city; // 都市の数 int [][] rg; // 都市間の距離 int kinbo; // 近傍探索(0:行わない,1:行う) int neib; // 近傍(2 or 3) int sel; // エッジの選択方法 // =0 : 最良のものを選択 // =1 : 最初のものを選択 int [][] city; //都市の位置データ /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : TSP定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ public TSP (String name1, String name2, int seed) : base(name1, seed) { string[] lines = File.ReadAllLines(name2); char[] charSep = new char[] {' '}; // 基本データの入力 // 1行目 string[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); out_lvl = int.Parse(str[1]); out_m = int.Parse(str[3]); // 2行目 str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); o_file = str[1]; out_d = int.Parse(str[3]); // 3行目 str = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries); kosa_m = int.Parse(str[1]); kosa = double.Parse(str[3]); k_point = int.Parse(str[5]); k_vr = int.Parse(str[7]); k_method = int.Parse(str[9]); k_bias = double.Parse(str[11]); k_step = double.Parse(str[13]); // 4行目 str = lines[3].Split(charSep, StringSplitOptions.RemoveEmptyEntries); mute_m = int.Parse(str[1]); mute = double.Parse(str[3]); wd = int.Parse(str[5]); m_mean = double.Parse(str[7]); m_std = double.Parse(str[9]); // 5行目 str = lines[4].Split(charSep, StringSplitOptions.RemoveEmptyEntries); elite = int.Parse(str[1]); s_method = int.Parse(str[3]); s_bias = double.Parse(str[5]); s_step = double.Parse(str[7]); // 6行目 str = lines[5].Split(charSep, StringSplitOptions.RemoveEmptyEntries); n_city = int.Parse(str[1]); max_gen = int.Parse(str[3]); // 7行目 str = lines[6].Split(charSep, StringSplitOptions.RemoveEmptyEntries); kinbo = int.Parse(str[1]); neib = int.Parse(str[3]); // 8行目 str = lines[7].Split(charSep, StringSplitOptions.RemoveEmptyEntries); sel = int.Parse(str[1]); if (kinbo > 0 && neib != 2 && neib != 3) { Console.WriteLine("***error 近傍の値が不適当"); Environment.Exit(1); } if (n_city != max_len) { Console.WriteLine("***error 都市数が不適当"); Environment.Exit(1); } // 都市の位置データ city = new int [n_city][]; for (int i1 = 0; i1 < n_city; i1++) { city[i1] = new int [2]; str = lines[i1+8].Split(charSep, StringSplitOptions.RemoveEmptyEntries); city[i1][0] = int.Parse(str[0]); city[i1][1] = int.Parse(str[1]); } // 距離テーブル rg = new int [n_city][]; for (int i1 = 0; i1 < n_city; i1++) { rg[i1] = new int [n_city]; for (int i2 = i1+1; i2 < n_city; i2++) { double x = city[i2][0] - city[i1][0]; double y = city[i2][1] - city[i1][1]; rg[i1][i2] = (int)(Math.Sqrt(x * x + y * y) + 0.5); } } for (int i1 = 1; i1 < n_city; i1++) { for (int i2 = 0; i2 < i1; i2++) rg[i1][i2] = rg[i2][i1]; } } /**************/ /* 全体の制御 */ /**************/ public void Control() { int gen = 1; // 初期集団の発生 Init_std(); // 評価 if (kinbo > 0) Kinbo(); else Adap(); // 画面表示 Console.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); // 出力 if (Math.Abs(out_lvl) > 0) Output(gen); // 世代交代 for (gen = 2; gen <= max_gen; gen++) { // 交叉 switch (kosa_m) { case -1: break; case 0: C_copy(2, max_ch/2, k_method, k_bias, k_step); // 親のコピー break; case 1: C_cycle(kosa, k_method, k_bias, k_step); // 循環交叉 break; case 2: C_part(kosa, k_method, k_bias, k_step); // 部分的交叉 break; case 3: C_seq(kosa, k_method, k_bias, k_step); // 順序交叉 break; case 4: C_useq(kosa, k_method, k_bias, k_step); // 一様順序交叉 break; case 5: C_upos(kosa, k_method, k_bias, k_step); // 一様位置交叉 break; case 6: C_edge(kosa, k_method, k_bias, k_step); // エッジ組み替え交叉 break; case 7: C_sub(kosa, k_point); // サブツアー交叉 break; default: break; } // 突然変異 switch (mute_m) { case -1: break; case 0: M_move(mute); // 移動 break; case 1: M_inv(mute, wd); // 逆位 break; case 2: M_scram(mute, wd); // スクランブル break; case 3: M_chg(mute, wd); // 転座 break; default: break; } // 適応度 if (kinbo > 0) Kinbo(); else Adap(); // 淘汰 S_roul(elite, s_method, s_bias, s_step); // 表示 if (gen%out_d == 0) Console.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); if (Math.Abs(out_lvl) > 0) { if (gen%Math.Abs(out_lvl) == 0) Output(gen); } } gen--; int k1 = out_m; out_m = 0; Console.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); Output(gen); out_m = k1; } /*********************************/ /* 距離の計算 */ /* n_c : 都市の数 */ /* p : 都市番号 */ /* return : 距離(負) */ /*********************************/ int Kyori(int n_c, int [] p) { int range = 0; int n1 = p[0]; int n2; for (int i1 = 1; i1 < n_c; i1++) { n2 = p[i1]; range -= rg[n1][n2]; n1 = n2; } n2 = p[0]; range -= rg[n1][n2]; return range; } /****************/ /* 適応度の計算 */ /****************/ void Adap() { int i1, k = 0; mean = 0.0; max = 0.0; max_n = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { pi_w[i1] = 2; pi[i1] = Kyori(len[i1], ind[i1]); } if (pi_w[i1] > 0) { k++; mean += pi[i1]; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } if (k > 0) mean /= k; } /**************************************/ /* エッジの入れ替え */ /* n_city : 都市の数 */ /* seq : 訪問する順番 */ /* r_m : 距離の負値 */ /* return : =0 : 改善がなかった */ /* =1 : 改善があった */ /**************************************/ int Change(int n_city, int [] seq, int [] r_m) { int ch = 0, i1, i2, i3, i4, k, k1, k2, max, n1, n2, n3, nn, r, sw = 0; max = r_m[0]; n3 = (int)(rn.NextDouble() * (n_city - 2)); if (n3 > n_city-3) n3 = n_city - 3; // 2近傍 for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { if (n3 == 0) n1 = n_city - 2; else n1 = n_city - 1; for (i2 = n3+2; i2 <= n1 && ch == 0; i2++) { // 枝の場所((n3,n3+1), (k1,k2)) k1 = i2; if (i2 == n_city-1) k2 = 0; else k2 = i2 + 1; // 枝の入れ替え kou1[0] = seq[n3]; k = 1; for (i3 = k1; i3 >= n3+1; i3--) { kou1[k] = seq[i3]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価 r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } } n3++; if (n3 > n_city-3) n3 = 0; } // 3近傍 if (neib == 3 && ch == 0) { for (i1 = 0; i1 <= n_city-3 && ch == 0; i1++) { n1 = n_city - 2; n2 = n_city - 1; for (i2 = n3+1; i2 <= n1 && ch == 0; i2++) { for (i3 = i2+1; i3 <= n2 && ch == 0; i3++) { // 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3; if (i3 == n_city-1) k2 = 0; else k2 = i3 + 1; // 枝の入れ替えと評価 // 入れ替え(その1) kou1[0] = seq[n3]; k = 1; for (i4 = i2; i4 >= n3+1; i4--) { kou1[k] = seq[i4]; k++; } for (i4 = k1; i4 >= i2+1; i4--) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その1) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その2) kou1[0] = seq[n3]; k = 1; for (i4 = k1; i4 >= i2+1; i4--) { kou1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その2) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その3) kou1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { kou1[k] = seq[i4]; k++; } for (i4 = i2; i4 >= n3+1; i4--) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その3) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } // 入れ替え(その4) kou1[0] = seq[n3]; k = 1; for (i4 = i2+1; i4 <= k1; i4++) { kou1[k] = seq[i4]; k++; } for (i4 = n3+1; i4 <= i2; i4++) { kou1[k] = seq[i4]; k++; } nn = k2; while (nn != n3) { kou1[k] = seq[nn]; k++; nn++; if (nn > n_city-1) nn = 0; } // 評価(その4) r = Kyori(n_city, kou1); if (r > max) { max = r; sw = 1; for (i3 = 0; i3 < n_city; i3++) kou2[i3] = kou1[i3]; if (sel > 0) ch = 1; } } } n3++; if (n3 > n_city-3) n3 = 0; } } // 設定 if (sw > 0) { r_m[0] = max; for (i1 = 0; i1 < n_city; i1++) seq[i1] = kou2[i1]; } return sw; } /**************/ /* 近傍の探索 */ /**************/ void Kinbo() { int i1, k = 0, sw; int[] r = new int [1]; max = 0.0; max_n = -1; mean = 0.0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { pi_w[i1] = 2; sw = 1; r[0] = Kyori(len[i1], ind[i1]); while (sw > 0) sw = Change(len[i1], ind[i1], r); pi[i1] = r[0]; } if (pi_w[i1] > 0) { k++; mean += pi[i1]; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } if (k > 0) mean /= k; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ void Output(int gen) { int pr = -1; if (out_lvl >= 0) { Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = int.Parse(Console.ReadLine()); } if (pr != 0) { StreamWriter OUT = new StreamWriter(o_file, true); // 出力先の決定と評価値の出力 if (pr < 0) { DateTime now = DateTime.Now; // 現在時刻の獲得 OUT.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 巡回順序の出力 if (out_m == 0) { int k = 0; for (int i1 = 0; i1 < len[max_n]; i1++) { int n = ind[max_n][i1]; if (pr < 0) OUT.WriteLine(n + " " + city[n][0] + " " + city[n][1]); else Console.WriteLine(n + " " + city[n][0] + " " + city[n][1]); if (pr > 0) { k++; if (k == pr) { Console.ReadLine(); k = 0; } } } } OUT.Close(); } } } /****************/ /* main program */ /****************/ class Program { static void Main(String[] args) { // 入力ミス if (args.Length == 0) Console.WriteLine("***error ケーススタディファイル名を入力して下さい\n"); // 入力OK else { // 入力データファイル名の入力 String[] lines = File.ReadAllLines(args[0]); int n = int.Parse(lines[0]); // 問題の数 String[] i_file1 = new String [n]; String[] i_file2 = new String [n]; char[] charSep = new char[] {' '}; for (int i1 = 0; i1 < n; i1++) { string[] str = lines[i1+1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); i_file1[i1] = str[0]; i_file2[i1] = str[1]; } // 実行(乱数の初期値を変える) for (int i1 = 0; i1 < n; i1++) { Console.WriteLine(); Console.WriteLine("+++++ケース " + (i1+1) + "+++++\n"); // 入力と初期設定 TSP tsp = new TSP (i_file1[i1], i_file2[i1], 1000 * i1 + 1234567); // 最適化 tsp.Control(); } } } } //----------------ケーススタディデータ(data_ct.txt)------ /* 3 data1_t.txt data2_t.txt data1_t.txt data2_t.txt data1_t.txt data2_t.txt */ //---------------Species記述データ(data1_t.txt)--------- /* 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 */ //---------------TSP記述データ(data2_t.txt)-------- /* 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */
/********************************************************************/ /* f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 */ /* coded by Y.Suganuma */ /********************************************************************/ using System; using System.IO; /***********************/ /* クラスSpeciesの定義 */ /***********************/ class Species { protected double max; // 最大適応度 protected double mean; // 平均適応度 protected double [] pi; // 適応度 protected double [] ro; // ルーレット板 protected int allele_u; // 対立遺伝子上限 protected int allele_l; // 対立遺伝子下限 protected int size; // 個体総数 protected int max_ch; // 子供の数の最大値 protected int max_len; // 最大遺伝子長 protected int min_len; // 最小遺伝子長(負の時は,最大遺伝子長で固定) protected int max_n; // 最大適応度の個体番号 protected int dup_a; // 遺伝子の重複 // =0 : 重複を許さない // =1 : 重複を許す protected int dup_s; // 個体の重複(同じ染色体の個体) // =0 : 重複を許さない // =1 : 重複を許す protected int [][] ind; // 集団(個体の集まり) protected int [] len; // 各個体の遺伝子長 protected int [] kou1; // 交叉・突然変異用作業場所1 protected int [] kou2; // 交叉・突然変異用作業場所2 protected int [] s_w; // 淘汰用指標(選択された回数) protected int [][] edge; // エッジ組み替え交叉用ワークエリア protected byte [] pi_w; // 適応度計算指標 // =0 : 未使用 // =1 : 適応度計算前(突然変異はこの個体だけに適用) // =2 : 適応度計算済み(交叉時に親とみなす) protected Random rn; // 乱数 /***********************************/ /* 正規分布変量の発生 */ /* m : 平均 */ /* s : 標準偏差 */ /* return : 正規分布変量 */ /***********************************/ double norm_d(double m, double s) { double x = 0.0; for (int i1 = 0; i1 < 12; i1++) x += rn.NextDouble(); x = s * (x - 6.0) + m; return x; } /**************************************************/ /* 場所を探す */ /* n : >=0 : n番目の親を捜す */ /* -1 : 空いている場所を探す */ /* return : 親の場所,または,空いている場所 */ /* (存在しないときは負の値) */ /**************************************************/ int Position(int n) { int i1, k = -1, sw = 0; // // 空いている場所を探す // if (n < 0) { for (i1 = 0; i1 < size+max_ch && k < 0; i1++) { if (pi_w[i1] == 0) k = i1; } if (k < 0) { Console.WriteLine("***error 空いている場所がない --Position--"); Environment.Exit(1); } } // // n番目の親(pi_w[i]=2)を捜す // else { for (i1 = 0; i1 < size+max_ch && sw == 0; i1++) { if (pi_w[i1] == 2) { k++; if (k == n) { sw = 1; k = i1; } } } } return k; } /*******************************************************************/ /* 個体の選択 */ /* method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* bias : α,または,method=2の場合は初期値 */ /* step : β */ /* return : 個体番号 */ /*******************************************************************/ int Select(int method, double bias, double step) { double sum = 0.0, x; int i1, k, min, n, sw; // ルーレット板の用意 switch (method) { // ランダム case -1: n = 0; 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; } break; // 評価値をそのまま利用 case 0: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { sum += pi[i1]; n++; } } if (Math.Abs(sum) > 1.0e-10) { sum = 1.0 / Math.Abs(sum); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = pi[i1] * sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 最小値からの差 case 1: min = -1; n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { n++; if (min < 0 || pi[i1] < pi[min]) min = i1; } } for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = pi[i1] - pi[min]; if (ro[i1] < bias) ro[i1] = bias; sum += ro[i1]; } } if (sum > 1.0e-10) { sum = 1.0 / sum; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } } else { sum = 1.0 / n; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] = sum; } } break; // 線形化 case 2: n = 0; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) { ro[i1] = -1.0; n++; } else ro[i1] = 1.0; } sw = 0; sum = bias; while (sw == 0) { min = -1; for (i1 = 0; i1 < size+max_ch; i1++) { if (ro[i1] < 0.0 && (min < 0 || pi[i1] < pi[min])) min = i1; } if (min < 0) sw = 1; else { ro[min] = sum; sum += step; } } sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n); for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] > 1) ro[i1] *= sum; } break; } 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; } /****************************/ /* コンストラクタ */ /* name : ファイル名 */ /* seed : 乱数の初期値 */ /****************************/ public Species (String name, int seed) { string[] lines = File.ReadAllLines(name); char[] charSep = new char[] {' '}; // // データの入力 // // 1行目 string[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); allele_u = int.Parse(str[1]); allele_l = int.Parse(str[3]); // 2行目 str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); max_len = int.Parse(str[1]); min_len = int.Parse(str[3]); // 3行目 str = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries); dup_a = int.Parse(str[1]); dup_s = int.Parse(str[3]); // 4行目 str = lines[3].Split(charSep, StringSplitOptions.RemoveEmptyEntries); size = int.Parse(str[1]); max_ch = int.Parse(str[3]); // // データのチェック // if (size <= 0) { Console.WriteLine("***error 個体総数≦0 (Constructor)"); Environment.Exit(1); } if (max_ch < 0) { Console.WriteLine("***error 子供の数<0 (Constructor)"); Environment.Exit(1); } if (max_len <= 0 || min_len == 0) { Console.WriteLine("***error 遺伝子長≦0 (Constructor)"); Environment.Exit(1); } if (max_len < min_len) { Console.WriteLine("***error 最大遺伝子長<最小遺伝子長 (Constructor)"); Environment.Exit(1); } if (allele_u <= allele_l) { Console.WriteLine("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)"); Environment.Exit(1); } int kind = allele_u - allele_l + 1; if (dup_a == 0 && max_len > kind) { Console.WriteLine("***error 遺伝子の重複を防ぐことはできない (Constructor)"); Environment.Exit(1); } // // 領域の確保 // int num = size + max_ch; ind = new int [num][]; for (int i1 = 0; i1 < num; i1++) ind[i1] = new int [max_len]; edge = new int [max_len][]; for (int i1 = 0; i1 < max_len; i1++) edge[i1] = new int [5]; pi = new double [num]; ro = new double [num]; len = new int [num]; kou1 = new int [max_len]; kou2 = new int [max_len]; s_w = new int [num]; pi_w = new byte [num]; // // 乱数の初期設定 // rn = new Random(seed); } /********************/ /* 標準的な初期設定 */ /********************/ protected void Init_std() { int i1, i2, i3, length, lid, 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) { // 遺伝子長の決定 if (min_len < 0) length = max_len; else { length = (int)(rn.NextDouble() * (max_len - min_len + 1) + min_len); if (length > max_len) length = max_len; } len[i1] = length; // 遺伝子の決定 for (i2 = 0; i2 < length; i2++) { sw2 = 0; while (sw2 == 0) { lid = (int)(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; ind[i1][i2] = lid; // 重複遺伝子のチェック sw2 = 1; if (dup_a == 0) { for (i3 = 0; i3 < i2 && sw2 > 0; i3++) { if (lid == ind[i1][i3]) sw2 = 0; } } } } // 重複個体のチェック sw1 = 1; if (dup_s == 0) { for (i2 = 0; i2 < i1 && sw1 > 0; i2++) { if (len[i1] == len[i2]) { sw2 = 0; for (i3 = 0; i3 < len[i1] && sw2 == 0; i3++) { if (ind[i1][i3] != ind[i2][i3]) sw2 = 1; } if (sw2 == 0) sw1 = 0; } } } } } } /****************************************************/ /* 標準的な出力 */ /* sw : 出力レベル */ /* =0 : 最終出力だけ */ /* n>0 : n世代毎に出力(負はファイル) */ /* out_m : 出力方法 */ /* =0 : すべての個体を出力 */ /* =1 : 最大適応度の個体だけを出力 */ /* gen : 現在の世代番号 */ /* name : 出力ファイル名 */ /****************************************************/ void Out_std(int sw, int out_m, int gen, String name) { int pr = -1; if (sw >= 0) { Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = int.Parse(Console.ReadLine()); } if (pr != 0) { StreamWriter OUT = new StreamWriter(name, true); // 出力先の決定と評価値の出力 if (pr < 0) { DateTime now = DateTime.Now; // 現在時刻の獲得 OUT.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 詳細出力 int k = 0; for (int i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { if (pr < 0) { OUT.Write(i1 + " allele"); for (int i2 = 0; i2 < len[i1]; i2++) OUT.Write(" " + ind[i1][i2]); OUT.WriteLine(" value " + pi[i1]); } else { Console.Write(i1 + " allele"); for (int i2 = 0; i2 < len[i1]; i2++) Console.Write(" " + ind[i1][i2]); Console.WriteLine(" value " + pi[i1]); } if (pr > 0) { k++; if (k == pr) { Console.ReadLine(); k = 0; } } } } OUT.Close(); } } /*******************************************************************/ /* 交叉(親のコピー) */ /* method : =2 : 有性(2つの親から2つの子供) */ /* =1 : 1つの親から1つの子供 */ /* pair : method=2 の時は親のペア数 */ /* method=1 の時は親の数(=子供の数) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_copy(int method, int pair, int k_method, double k_bias, double k_step) { int i1, i2, i3, k, p, p1, p2 = 0, sw; // // 初期設定とデータチェック // if (method != 1) method = 2; if (pair <= 0) pair = (method==2) ? max_ch/2 : max_ch; else { if (method == 2 && 2*pair > max_ch || method == 1 && pair > max_ch) { Console.WriteLine("***error 子供が多すぎる (C_copy)"); Environment.Exit(1); } } // // 実行 // for (i1 = 0; i1 < pair; i1++) { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // コピー for (i2 = 0; i2 < method; i2++) { p = (i2 == 0) ? p1 : p2; k = Position(-1); len[k] = len[p]; pi_w[k] = 1; for (i3 = 0; i3 < len[k]; i3++) ind[k][i3] = ind[p][i3]; } } } /*******************************************************************/ /* 交叉(多点交叉) */ /* kosa : 交叉確率 */ /* k_point : 交叉点の数 */ /* (負の時は,1から-k_point間のランダム) */ /* k_vr : =0 : 両親とも同じ位置で交叉 */ /* =1 : 両親が異なる位置で交叉(遺伝子長は可変) */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_point(double kosa, int k_point, int k_vr, int k_method, double k_bias, double k_step) { int abs_p, c1, c2, i1, i2, i3, k1, k2, mn = 0, num, p1, p2 = 0, pair, sw, t11, t12, t21, t22; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a == 0) { Console.WriteLine("***error 交叉方法が不適当 (C_point)"); Environment.Exit(1); } abs_p = Math.Abs(k_point); if (abs_p == 0 || abs_p > max_len-1 || min_len > 0 && abs_p > min_len-1) { Console.WriteLine("***error 交叉点の数が不適当 (C_point)"); Environment.Exit(1); } if (k_vr > 0 && min_len < 0) { Console.WriteLine("***error 遺伝子長は可変でなければならない (C_point)"); Environment.Exit(1); } // // 交叉 // num = k_point; for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 交叉位置の数の決定 if (k_point < 0) { num = (int)(rn.NextDouble() * abs_p + 1); if (num > abs_p) num = abs_p; } // 交叉位置の決定(点の後ろで交叉) for (i2 = 0; i2 < num; i2++) { // 親1の交叉位置 sw = 0; while (sw == 0) { sw = 1; kou1[i2] = (int)(rn.NextDouble() * (len[p1] - 1)); if (kou1[i2] > len[p1]-2) kou1[i2] = len[p1] - 2; if (k_vr == 0 && kou1[i2] > len[p2]-2) kou1[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou1[i3] == kou1[i2]) sw = 0; } } // 親2の交叉位置 if (k_vr > 0) { sw = 0; while (sw == 0) { sw = 1; kou2[i2] = (int)(rn.NextDouble() * (len[p2] - 1)); if (kou2[i2] > len[p2]-2) kou2[i2] = len[p2] - 2; for (i3 = 0; i3 < i2 && sw > 0; i3++) { if (kou2[i3] == kou2[i2]) sw = 0; } } } } // 交叉の実行 // 親1のt11からt12を子1のc1へコピー // 親2のt21からt22を子2のc2へコピー // 次は, // 親1のt11からt12を子2のc2へコピー // 親2のt21からt22を子1のc1へコピー // ・・・・・ c1 = 0; c2 = 0; t11 = 0; t21 = 0; // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; for (i2 = 0; i2 < num+1; i2++ ) { // 次の交叉位置を求める if (i2 == num) { // 最後 t12 = len[p1]; t22 = len[p2]; } else { // 親1 t12 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou1[i3] >= 0 && kou1[i3] <= t12) { t12 = kou1[i3]; mn = i3; } } kou1[mn] = -1; t12++; // 親2 if (k_vr == 0) t22 = t12; else { t22 = max_len; for (i3 = 0; i3 < num; i3++) { if (kou2[i3] >= 0 && kou2[i3] <= t22) { t22 = kou2[i3]; mn = i3; } } kou2[mn] = -1; t22++; } } // 指定箇所のコピー for (i3 = t11; i3 < t12; i3++) { if (i2%2 == 0) { if (c1 < max_len) { ind[k1][c1] = ind[p1][i3]; c1++; } } else { if (c2 < max_len) { ind[k2][c2] = ind[p1][i3]; c2++; } } } for (i3 = t21; i3 < t22; i3++) { if (i2%2 == 0) { if (c2 < max_len) { ind[k2][c2] = ind[p2][i3]; c2++; } } else { if (c1 < max_len) { ind[k1][c1] = ind[p2][i3]; c1++; } } } // 交叉位置の移動 t11 = t12; t21 = t22; } } } } /*******************************************************************/ /* 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば, */ /* 親1,0であれば親2の遺伝子を子1が受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_uniform(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k1, k2, p1, p2 = 0, pair, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a == 0) { Console.WriteLine("***error 交叉方法が不適当 (C_uniform)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_uniform)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; 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]; } } } } } /*******************************************************************/ /* 交叉(平均化交叉.2つの親の平均値を受け継ぐ) */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_mean(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, k, p1, p2 = 0, sw; // // 初期設定とデータのチェック // if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_mean)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < max_ch; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); len[k] = len[p1]; pi_w[k] = 1; // 交叉 for (i2 = 0; i2 < len[k]; i2++) ind[k][i2] = (ind[p1][i2] + ind[p2][i2]) / 2; } } } /*******************************************************************/ /* 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を */ /* そのまま各子供が選択する.その位置にある親2(1)の遺伝 */ /* 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 */ /* ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 */ /* 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り */ /* 返し,残りの遺伝子については,子1(2)は,親2(1)の */ /* 遺伝子をその順番通りに受け継ぐ) */ /* 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 */ /* * → → */ /* 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_cycle(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_cycle)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_cycle)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 初期設定 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = 0; kou2[i2] = 0; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 sw = 0; while (sw == 0) { sw = 1; p = (int)(rn.NextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; if (kou1[p] == 0 && kou2[p] == 0) { kou1[p] = 1; kou2[p] = 1; ind[k1][p] = ind[p1][p]; ind[k2][p] = ind[p2][p]; for (i2 = 0; i2 < len[p1] && sw > 0; i2++) { if (ind[p2][p] == ind[p1][i2]) { ind[k1][i2] = ind[p1][i2]; kou1[i2] = 1; sw = 0; } } sw = 1; for (i2 = 0; i2 < len[p2] && sw > 0; i2++) { if (ind[p1][p] == ind[p2][i2]) { ind[k2][i2] = ind[p2][i2]; kou2[i2] = 1; sw = 0; } } } } sw = 0; i2 = 0; i3 = 0; while (sw == 0) { while (sw == 0 && i2 < len[p1]) { if (kou1[i2] == 0) sw = 1; else i2++; } sw = 0; while (sw == 0 && i3 < len[p2]) { if (kou2[i3] == 0) sw = 1; else i3++; } if (i2 < len[p1] && i3 < len[p2]) { ind[k1][i2] = ind[p2][i3]; ind[k2][i3] = ind[p1][i2]; sw = 0; i2++; i3++; } else sw = 1; } } } } /*******************************************************************/ /* 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と */ /* 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ */ /* の2つの遺伝子の位置を交換する.この操作を,選択した点よ */ /* り右にあるすべての遺伝子に対して実施する */ /* 2 4 1 3 6 5 2 4 5 3 6 1 */ /* * → → ・・・・・ */ /* 3 2 5 4 1 6 3 2 1 4 5 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_part(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, lv, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_part)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_part)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.NextDouble() * len[p1]); if (p >= len[p1]) p = len[p1] - 1; for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } for (i2 = p; i2 < len[p1]; i2++) { sw = 0; lv = ind[k1][i2]; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (ind[k2][i2] == ind[k1][i3]) { ind[k1][i2] = ind[k1][i3]; ind[k1][i3] = lv; sw = 1; } } sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (lv == ind[k2][i3]) { ind[k2][i3] = ind[k2][i2]; ind[k2][i2] = lv; sw = 1; } } } } } } /*******************************************************************/ /* 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の */ /* 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 */ /* の遺伝子を親2の遺伝子の出現順序に並べ替える. */ /* 2 4 1 3 6 5 2 4 1 3 5 6 */ /* * → */ /* 3 2 5 4 1 6 3 2 5 4 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_seq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, pp, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_seq)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_seq)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 p = (int)(rn.NextDouble() * (len[p1] - 1)); if (p >= len[p1]-1) p = len[p1] - 2; for (i2 = 0; i2 <= p; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; } pp = 0; for (i2 = p+1; i2 < len[p1]; i2++) { sw = 0; for (i3 = pp; i3 < len[p2] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4]) { sw = 1; pp = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } pp = 0; for (i2 = p+1; i2 < len[p2]; i2++) { sw = 0; for (i3 = pp; i3 < len[p1] && sw == 0; i3++) { for (i4 = p+1; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4]) { sw = 1; pp = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } /*******************************************************************/ /* 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の順序に従って,他の親の遺伝子 */ /* を並べ替える */ /* 2 4 1 3 6 5 2 4 1 3 6 5 */ /* * * → */ /* 3 2 5 4 1 6 4 2 5 3 1 6 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_useq(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, k1, k2, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_useq)\n"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_useq)\n"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { ind[k1][i2] = ind[p1][i2]; ind[k2][i2] = ind[p2][i2]; kou1[i2] = (rn.NextDouble() < 0.5) ? 0 : 1; } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p2] && sw == 0; i3++) { for (i4 = 0; i4 < len[p1] && sw == 0; i4++) { if (ind[p2][i3] == ind[p1][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k1][i2] = ind[p1][i4]; } } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { if (kou1[i2] > 0) { sw = 0; for (i3 = p; i3 < len[p1] && sw == 0; i3++) { for (i4 = 0; i4 < len[p2] && sw == 0; i4++) { if (ind[p1][i3] == ind[p2][i4] && kou1[i4] > 0) { sw = 1; p = i3 + 1; ind[k2][i2] = ind[p2][i4]; } } } } } } } } /*******************************************************************/ /* 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 */ /* 択された位置における遺伝子の位置に,他の親の同じ遺伝子を */ /* 配置する.残りの遺伝子は,親と同じ順序に配置する. */ /* 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 */ /* * * → → */ /* 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_upos(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, k1, k2, p, pair, p1, p2 = 0, sw; // // 初期設定とデータのチェック // pair = max_ch / 2; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_upos)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_upos)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p2]; // 交叉 for (i2 = 0; i2 < len[p1]; i2++) { kou1[i2] = (rn.NextDouble() < 0.5) ? 0 : 1; if (kou1[i2] > 0) { ind[k1][i2] = ind[p2][i2]; ind[k2][i2] = ind[p1][i2]; } } p = 0; for (i2 = 0; i2 < len[p1]; i2++) { sw = 0; for (i3 = 0; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p1][i2] == ind[k1][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p1] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k1][i3] = ind[p1][i2]; p = i3 + 1; sw = 1; } } } } p = 0; for (i2 = 0; i2 < len[p2]; i2++) { sw = 0; for (i3 = 0; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] > 0 && ind[p2][i2] == ind[k2][i3]) sw = 1; } if (sw == 0) { for (i3 = p; i3 < len[p2] && sw == 0; i3++) { if (kou1[i3] == 0) { ind[k2][i3] = ind[p2][i2]; p = i3 + 1; sw = 1; } } } } } } } /*******************************************************************/ /* 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は */ /* 0~(max_len-1)である必要がある) */ /* (0) エッジマップを作成する.エッジマップとは,2つの親 */ /* を見て,ノードがどこに接続されているのかを表すもの */ /* であり,例えば,2つの親が, */ /* [A B C D E F] */ /* [B D C A E F] */ /* である場合は, */ /* A : B F C E */ /* B : A C D F */ /* C : B D A */ /* D : C E B */ /* E : D F A */ /* F : A E B */ /* となる. */ /* (1) 両親の2つの出発点の内1つで初期化する.ランダムま */ /* たはステップ(4)の基準に従って選ぶ(現在のノード) */ /* (2) エッジマップから,現在のノードを除く */ /* (3) 現在のノードが接続先のノードを持っていたら,(4)に */ /* 進む.さもなければ,(5)に進む */ /* (4) 現在のノードが持っている接続先ノードの内,最も少な */ /* い接続先ノードを持ったノードを選択し(同じ条件の場 */ /* 合は,ランダム),それを現在のノードとし,(2)に進む */ /* (5) 未接続のノードが残っていればランダムに選択し,(2)に */ /* 戻る.さもなければ,終了する */ /* kosa : 交叉確率 */ /* k_method : 選択方法 */ /* =-1 : ランダム */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* k_bias : α,または,method=2の場合は初期値 */ /* k_step : β */ /*******************************************************************/ protected void C_edge(double kosa, int k_method, double k_bias, double k_step) { int i1, i2, i3, i4, i5, k, kk, k0 = 0, k1, k2, min, num, p, pair, p1, p2 = 0, sw; int[] e = new int [2]; // // 初期設定とデータのチェック // pair = max_ch; if (dup_a != 0) { Console.WriteLine("***error 交叉方法が不適当 (C_edge)"); Environment.Exit(1); } if (min_len > 0) { Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_edge)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < pair; i1++) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(1, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 親の選択 p1 = Select(k_method, k_bias, k_step); sw = 0; while (sw == 0) { p2 = Select(k_method, k_bias, k_step); if (p1 != p2) sw = 1; } // 遺伝子長 k = Position(-1); pi_w[k] = 1; len[k] = len[p1]; // エッジマップの初期化 for (i2 = 0; i2 < len[k]; i2++) { edge[i2][0] = 0; for (i3 = 1; i3 <= 4; i3++) edge[i2][i3] = -1; } // 交叉 // エッジマップの作成 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p1][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p1][len[k]-1]; e[1] = ind[p1][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p1][i3-1]; e[1] = ind[p1][0]; } else { e[0] = ind[p1][i3-1]; e[1] = ind[p1][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } sw = 0; for (i3 = 0; i3 < len[k] && sw == 0; i3++) { if (i2 == ind[p2][i3]) { sw = 1; if (i3 == 0) { e[0] = ind[p2][len[k]-1]; e[1] = ind[p2][1]; } else { if (i3 == len[k]-1) { e[0] = ind[p2][i3-1]; e[1] = ind[p2][0]; } else { e[0] = ind[p2][i3-1]; e[1] = ind[p2][i3+1]; } } for (i4 = 0; i4 < 2; i4++) { sw = 1; for (i5 = 1; i5 <= edge[i2][0] && sw == 1; i5++) { if (edge[i2][i5] == e[i4]) sw = 2; } if (sw == 1) { edge[i2][0]++; edge[i2][edge[i2][0]] = e[i4]; } } } } } // 交叉の実行 // 出発点の決定 k1 = ind[p1][0]; k2 = ind[p2][0]; if (edge[k1][0] == edge[k2][0]) kk = (rn.NextDouble() > 0.5) ? k2 : k1; else kk = (edge[k1][0] < edge[k2][0]) ? k1 : k2; ind[k][0] = kk; p = 1; while (p < len[k]) { // ノードの除去 for (i2 = 0; i2 < len[k]; i2++) { sw = 0; if (edge[i2][0] > 0) { for (i3 = 1; i3 <= 4 && sw == 0; i3++) { if (edge[i2][i3] == kk) { sw = 1; edge[i2][i3] = -1; edge[i2][0]--; } } } } // 次の現在ノードの選択 min = 10; num = 0; for (i2 = 1; i2 <= 4; i2++) { if (edge[kk][i2] >= 0) { k1 = edge[kk][i2]; if (edge[k1][0] >= 0 && edge[k1][0] < min) { num = 1; min = edge[k1][0]; k0 = k1; } else { if (edge[k1][0] == min) num++; } } } if (num > 1) { k1 = (int)(rn.NextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 1; i2 <= 4 && k0 < 0; i2++) { if (edge[kk][i2] >= 0) { if (edge[edge[kk][i2]][0] == min) { k2++; if (k1 == k2) k0 = edge[kk][i2]; } } } } else { if (num <= 0) { num = 0; for (i2 = 0; i2 < len[k]; i2++) { if (i2 != kk && edge[i2][0] >= 0) num++; } if (num <= 0) { Console.WriteLine("***error invalid data (C_edge)"); Environment.Exit(1); } else { k1 = (int)(rn.NextDouble() * num) + 1; if (k1 > num) k1 = num; k2 = 0; k0 = -1; for (i2 = 0; i2 < len[k] && k0 < 0; i2++) { if (i2 != kk && edge[i2][0] >= 0) { k2++; if (k1 == k2) k0 = i2; } } } } } edge[kk][0] = -1; ind[k][p] = k0; kk = k0; p++; } } } } /*************************************************************/ /* 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に*/ /* 同じ遺伝子のグループがない限り実行されない.たとえば*/ /* ***abcd** */ /* *cdab**** */ /* のような両親の時実行され,以下の4つの子供が生成され*/ /* る) */ /* ***cdab** */ /* *abcd**** */ /* ***badc** */ /* *dcba**** */ /* 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 */ /* 供が生成される可能性があるので,子供の数としてこの値*/ /* 以上のデータを入力しておく必要がある. */ /* kosa : 交叉確率 */ /* count : 1つのペアーに対する交差回数 */ /*************************************************************/ protected void C_sub(double kosa, int count) { int i1, i2, i3, i4, i5, k1, k2, k3, k4, p1, p2, t11, t12 = 0, t21, t22 = 0, sw; // // 初期設定とデータのチェック // if ((4*count*size*(size-1)) > max_ch) { Console.WriteLine("***error 子供が多すぎる (C_sub)"); Environment.Exit(1); } // // 交叉 // for (i1 = 0; i1 < size-1; i1++) { // 親1 p1 = Position(i1); if (p1 >= 0) { for (i2 = i1; i2 < size; i2++) { // 親2 p2 = Position(i2); if (p2 >= 0) { // 交叉しない場合 if (rn.NextDouble() > kosa) C_copy(2, 1, -1, 0.0, 0.0); // 交叉する場合 else { // 交叉回数の制御 for (i3 = 0; i3 < count; i3++) { // 交叉位置の決定(点の後ろで交叉) // 親1の交叉位置 t11 = (int)(rn.NextDouble() * len[p1]); if (t11 > (len[p1]-1)) t11 = len[p1] - 1; sw = 0; while (sw == 0) { t12 = (int)(rn.NextDouble() * len[p1]); if (t12 > (len[p1]-1)) t12 = len[p1] - 1; if (t12 != t11) sw = 1; } if (t11 > t12) { k1 = t11; t11 = t12; t12 = k1; } // 親2の交叉位置 sw = 0; t21 = -1; for (i4 = 0; i4 < len[p2] && t21 < 0; i4++) { for (i5 = t11; i5 <= t12 && t21 < 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) t21 = i4; } } if (t21 >= 0) { t22 = t21 + t12 - t11; if (t22 < len[p2]) { sw = 1; for (i4 = t21+1; i4 <= t22 && sw > 0; i4++) { sw = 0; for (i5 = t11; i5 <= t12 && sw == 0; i5++) { if (ind[p2][i4] == ind[p1][i5]) sw = 1; } } } } // 交叉の実行 if (sw > 0) { k1 = Position(-1); pi_w[k1] = 1; len[k1] = len[p1]; k2 = Position(-1); pi_w[k2] = 1; len[k2] = len[p1]; k3 = Position(-1); pi_w[k3] = 1; len[k3] = len[p2]; k4 = Position(-1); pi_w[k4] = 1; len[k4] = len[p2]; for (i4 = 0; i4 < t11; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = t11; i4 <= t12; i4++) { ind[k1][i4] = ind[p2][t21+i4-t11]; ind[k2][i4] = ind[p2][t22-i4+t11]; } for (i4 = t12+1; i4 < len[p1]; i4++) { ind[k1][i4] = ind[p1][i4]; ind[k2][i4] = ind[p1][i4]; } for (i4 = 0; i4 < t21; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } for (i4 = t21; i4 <= t22; i4++) { ind[k3][i4] = ind[p1][t11+i4-t21]; ind[k4][i4] = ind[p1][t12-i4+t21]; } for (i4 = t22+1; i4 < len[p2]; i4++) { ind[k3][i4] = ind[p2][i4]; ind[k4][i4] = ind[p2][i4]; } } } } } } } } } /**************************************/ /* 突然変異(対立遺伝子との置き換え) */ /* pr : 突然変異率 */ /**************************************/ protected void M_alle(double pr) { int i1, i2, lid; // // データのチェックと初期設定 // if (dup_a == 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_alle)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.NextDouble() <= pr) { lid = (int)(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l); if (lid > allele_u) lid = allele_u; if (lid != ind[i1][i2]) ind[i1][i2] = lid; } } } } } /**********************************************************************/ /* 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に */ /* 移動する) */ /* pr : 突然変異率 */ /**********************************************************************/ protected void M_move(double pr) { int i1, i2, ld, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 位置の決定 // // p1 p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p2 sw = 0; while (sw == 0) { p2 = (int)(rn.NextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } // // 実行 // if (p2 > p1) { ld = ind[i1][p2]; for (i2 = p2; i2 > p1; i2--) ind[i1][i2] = ind[i1][i2-1]; ind[i1][p1] = ld; } else { ld = ind[i1][p2]; for (i2 = p2; i2 < p1-1; i2++) ind[i1][i2] = ind[i1][i2+1]; ind[i1][p1-1] = ld; } } } } /********************************************************/ /* 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /********************************************************/ protected void M_inv(double pr, int wd) { int i1, lid, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 区間の決定 // if (wd == 0) { p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.NextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.NextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } // // 実行 // sw = 0; while (sw == 0) { lid = ind[i1][p1]; ind[i1][p1] = ind[i1][p2]; ind[i1][p2] = lid; p1++; p2--; if (p1 >= p2) sw = 1; } } } } /**********************************************************************/ /* 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_scram(double pr, int wd) { int i1, i2, ld, p, p1, p2 = 0, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 区間の決定 // if (wd == 0) { p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; sw = 0; while (sw == 0) { p2 = (int)(rn.NextDouble() * len[i1]); if (p2 >= len[i1]) p2 = len[i1] - 1; if (p2 != p1) sw = 1; } if (p1 > p2) { p = p1; p1 = p2; p2 = p; } } else { p1 = len[i1]; while (p1 > len[i1]-2) p1 = (int)(rn.NextDouble() * len[i1]); p2 = p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; } // // 実行 // for (i2 = p1; i2 <= p2; i2++) { p = (int)(rn.NextDouble() * (p2 - p1 + 1) + p1); if (p > p2) p = p2; ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; } } } } /**********************************************************************/ /* 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし */ /* 重複部分はそのままとする) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_chg(double pr, int wd) { int i1, i2, ld, p, p1, p2, p3 = 0, p4, sw; for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // // 区間等の決定([p1,p2]と[p3,p4]の入れ替え) // // p1 p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.NextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 小さい方をp1,p2にする if (p1 > p3) { p = p1; p1 = p3; p3 = p; } // p4, p2 p4 = (wd == 0) ? (int)(rn.NextDouble() * (len[i1] - p3)) + p3 : p1 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); // 重複部分のチェック if (p2 >= p3) { p = p3 - 1; p3 = p2 + 1; p2 = p; p4 = p3 + (p2 - p1); } // // 実行 // p = p3; for (i2 = p1; i2 <= p2; i2++) { ld = ind[i1][i2]; ind[i1][i2] = ind[i1][p]; ind[i1][p] = ld; p++; } } } } /**********************************************************************/ /* 突然変異(重複.2点間の遺伝子を他の位置にコピーする */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_dup(double pr, int wd) { int i1, i2, p, p1, p2, p3 = 0, p4, sw; // // データのチェック // if (dup_a == 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_dup)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // 区間の決定([p1,p2]を[p3,p4]にコピー) // p1 p1 = (int)(rn.NextDouble() * len[i1]); if (p1 >= len[i1]) p1 = len[i1] - 1; // p3 sw = 0; while (sw == 0) { p3 = (int)(rn.NextDouble() * len[i1]); if (p3 >= len[i1]) p3 = len[i1] - 1; if (p3 != p1) sw = 1; } // 区間を決める if (p3 > p1) { p4 = (wd == 0) ? (int)(rn.NextDouble() * (len[i1] - p3)) + p3 : p3 + wd - 1; if (p4 >= len[i1]) p4 = len[i1] - 1; p2 = p1 + (p4 - p3); } else { p2 = (wd == 0) ? (int)(rn.NextDouble() * (len[i1] - p1)) + p1 : p1 + wd - 1; if (p2 >= len[i1]) p2 = len[i1] - 1; p4 = p3 + (p2 - p1); } // 実行 p = p4; for (i2 = p2; i2 >= p1; i2--) { ind[i1][p] = ind[i1][i2]; p--; } } } } /******************************************************/ /* 突然変異(摂動.値をある量だけ変化させる) */ /* pr : 突然変異率 */ /* method : =0 : 正規分布 */ /* =1 : 一様分布 */ /* m : 平均または一様分布の下限 */ /* s : 標準偏差または一様分布の上限 */ /******************************************************/ protected void M_per(double pr, int method, double m, double s) { double w, wd = 0.0, x1; int i1, i2; // // データのチェックと初期設定 // if (dup_a == 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_per)"); Environment.Exit(1); } if (method > 0) wd = s - m; // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { for (i2 = 0; i2 < len[i1]; i2++) { if (rn.NextDouble() <= pr) { if (method == 0) w = norm_d(m, s); else { w = rn.NextDouble() * wd; if (rn.NextDouble() < 0.5) w = -w; } x1 = (double)ind[i1][i2] + w; if (x1 > allele_u) x1 = allele_u; else { if (x1 < allele_l) x1 = allele_l; } ind[i1][i2] = (int)x1; } } } } } /**********************************************************************/ /* 突然変異(挿入.ある長さの遺伝子を挿入する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_ins(double pr, int wd) { int i1, i2, l, ld, p; // // データのチェック // if (dup_a == 0 || min_len < 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_ins)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // 挿入位置の決定 p = (int)(rn.NextDouble() * (len[i1]+1)); if (p > len[i1]) p = len[i1]; // 挿入する遺伝子長の決定 l = (wd == 0) ? (int)(rn.NextDouble() * (max_len - len[i1] + 1)) : wd; if (l > max_len-len[i1]) l = max_len - len[i1]; else { if (l <= 0) l = 1; } // 実行 // 挿入場所の確保 if (p < len[i1]) { for (i2 = len[i1]+l-1; i2 >= p; i2--) ind[i1][i2] = ind[i1][i2-l]; } // 挿入場所の遺伝子の決定 for (i2 = p; i2 < p+l; i2++) { ld = (int)(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l); if (ld > allele_u) ld = allele_u; ind[i1][i2] = ld; } len[i1] += l; } } } /**********************************************************************/ /* 突然変異(削除.ある長さの遺伝子を削除する) */ /* pr : 突然変異率 */ /* wd : >0 : 幅を固定 */ /* =0 : 幅をランダム */ /**********************************************************************/ protected void M_del(double pr, int wd) { int i1, i2, l, max, p; // // データのチェック // if (dup_a == 0 || min_len < 0) { Console.WriteLine("***error 突然変異方法が不適当 (M_del)"); Environment.Exit(1); } // // 実行 // for (i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1 && rn.NextDouble() <= pr) { // 削除位置の決定 p = (int)(rn.NextDouble() * len[i1]); if (p >= len[i1]) p = len[i1] - 1; // 削除する遺伝子長の決定 max = (len[i1]-min_len < len[i1]-p) ? len[i1] - min_len : len[i1] - p; l = (wd == 0) ? (int)(rn.NextDouble() * max + 1) : wd; if (l > max) l = max; // 実行 for (i2 = 0; i2 < len[i1]-p-l; i2++) ind[i1][p+i2] = ind[i1][p+i2+l]; len[i1] -= l; } } } /*********************************************************************/ /* 淘汰(エリート・ルーレット選択) */ /* elite : エリートで残す個体数(default=0) */ /* s_method : ルーレット板の作成方法(default=1) */ /* =0 : 適応度をそのまま使用 */ /* =1 : 最小値からの差(ただし,α以下の場合はα) */ /* =2 : 評価値に順位をつけ,減少率βで線形化 */ /* s_bias : α,または,method=2の場合は初期値(default=0) */ /* s_step : β(default=1) */ /*********************************************************************/ protected void S_roul(int elite, int s_method, double s_bias, double s_step) { int count = 0, i1, i2, i3, k = 0, max, n = 0, p, sw; // // 値のチェックと初期設定 // if (s_method != 0 && s_method != 2) s_method = 1; if (elite > size) { Console.WriteLine("***error エリートで残す数が多すぎる (S_roul)"); Environment.Exit(1); } if (s_method == 2 && s_step <= 0.0) s_step = 1.0; for (i1 = 0; i1 < size+max_ch; i1++) s_w[i1] = 0; // // 重複個体を削除 // if (dup_s == 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 && len[i1] == len[i2]) { sw = 0; for (i3 = 0; i3 < len[i1] && 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 || dup_s == 0 && n < size) { Console.WriteLine("***error 残す個体がない (S_roul)"); Environment.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++; } } // ルーレット選択 while (count < size+max_ch && k < size) { p = Select(s_method, s_bias, s_step); if (dup_s == 0 && s_w[p] > 0) count++; else { count = 0; s_w[p]++; k++; } } // 選択に失敗した場合の処理 if (dup_s == 0 && k < size) { for (i1 = 0; i1 < size+max_ch && k < size; 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(-1); len[k] = len[i1]; pi_w[k] = 2; pi[k] = pi[i1]; for (i3 = 0; i3 < len[i1]; i3++) ind[k][i3] = ind[i1][i3]; } } } } } } /************************/ /* クラスFunctionの定義 */ /************************/ class Function : Species { double cv; // 2進数を10進数の変換する係数 int max_gen; // 最大世代交代数 int kosa_m; // 交叉方法 // =-1 : 交叉を使用しない // =0 : 親のコピー // =1 : 多点交叉 // =2 : 一様交叉 // =3 : 平均化交叉 double kosa; // 交叉確率 int k_point; // 交差点の数(負の時は,1から-point間のランダム) int k_vr; // =0 : 両親とも同じ位置で交叉 // =1 : 両親が異なる位置で交叉(遺伝子長は可変) int k_method; // 交叉の時の親の選択方法 // =-1 : ランダム // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double k_bias; // α,または,method=2の場合は初期値 double k_step; // β int mute_m; // 突然変異方法 // =-1 : 突然変異を使用しない // =0 : 対立遺伝子への置換 // =1 : 移動 // =2 : 逆位 // =3 : スクランブル // =4 : 転座 // =5 : 重複 // =6 : 摂動 double mute; // 突然変異率 int wd; // 突然変異に使用する部分遺伝子長 double m_mean; // 摂動の平均値 double m_std; // 摂動の標準偏差 int elite; // エリート選択で残す数 int s_method; // ルーレット板の作成方法 // =0 : 適応度をそのまま使用 // =1 : 最小値からの差(ただし,α以下の場合はα) // =2 : 評価値に順位をつけ,減少率βで線形化 double s_bias; // α,または,s_method=2の場合は初期値 double s_step; // β int out_d; // 表示間隔 int out_lvl; // 出力レベル // =0 : 最終出力だけ // n>0 : n世代毎に出力(負の時はファイル) int out_m; // 出力方法 // =0 : すべてを出力 // =1 : 最大適応度の個体だけを出力 String o_file; // 出力ファイル名 /***************************************/ /* コンストラクタ */ /* name1 : Species定義ファイル名 */ /* name2 : Function定義ファイル名 */ /* seed : 乱数の初期値 */ /***************************************/ public Function (String name1, String name2, int seed) : base(name1, seed) { string[] lines = File.ReadAllLines(name2); char[] charSep = new char[] {' '}; // 基本データの入力 // 1行目 string[] str = lines[0].Split(charSep, StringSplitOptions.RemoveEmptyEntries); out_lvl = int.Parse(str[1]); out_m = int.Parse(str[3]); // 2行目 str = lines[1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); o_file = str[1]; out_d = int.Parse(str[3]); // 3行目 str = lines[2].Split(charSep, StringSplitOptions.RemoveEmptyEntries); kosa_m = int.Parse(str[1]); kosa = double.Parse(str[3]); k_point = int.Parse(str[5]); k_vr = int.Parse(str[7]); k_method = int.Parse(str[9]); k_bias = double.Parse(str[11]); k_step = double.Parse(str[13]); // 4行目 str = lines[3].Split(charSep, StringSplitOptions.RemoveEmptyEntries); mute_m = int.Parse(str[1]); mute = double.Parse(str[3]); wd = int.Parse(str[5]); m_mean = double.Parse(str[7]); m_std = double.Parse(str[9]); // 5行目 str = lines[4].Split(charSep, StringSplitOptions.RemoveEmptyEntries); elite = int.Parse(str[1]); s_method = int.Parse(str[3]); s_bias = double.Parse(str[5]); s_step = double.Parse(str[7]); // 6行目 str = lines[5].Split(charSep, StringSplitOptions.RemoveEmptyEntries); max_gen = int.Parse(str[1]); cv = 1.0 / (Math.Pow(2.0, (double)max_len) - 1.0); } /**************/ /* 全体の制御 */ /**************/ public void Control() { int gen = 1; // 初期集団の発生 Init_std(); // 評価 Adap(); // 出力 Console.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); if (Math.Abs(out_lvl) > 0) Output(gen); // 世代交代 for (gen = 2; gen <= max_gen; gen++) { // 交叉 switch (kosa_m) { case -1: break; case 0: C_copy(2, max_ch/2, k_method, k_bias, k_step); // 親のコピー break; case 1: C_point(kosa, k_point, k_vr, k_method, k_bias, k_step); // 多点交叉 break; case 2: C_uniform(kosa, k_method, k_bias, k_step); // 一様交叉 break; case 3: C_mean(kosa, k_method, k_bias, k_step); // 平均化交叉 break; default: break; } // 突然変異 switch (mute_m) { case -1: break; case 0: M_alle(mute); // 対立遺伝子への置換 break; case 1: M_move(mute); // 移動 break; case 2: M_inv(mute, wd); // 逆位 break; case 3: M_scram(mute, wd); // スクランブル break; case 4: M_chg(mute, wd); // 転座 break; case 5: M_dup(mute, wd); // 重複 break; case 6: M_per(mute, wd, m_mean, m_std); // 摂動 break; default: break; } // 適応度 Adap(); // 淘汰 S_roul(elite, s_method, s_bias, s_step); // 出力 if (gen%out_d == 0) Console.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); if (Math.Abs(out_lvl) > 0) { if (gen%Math.Abs(out_lvl) == 0) Output(gen); } } gen--; int k1 = out_m; out_m = 0; Console.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean); Output(gen); out_m = k1; } /****************/ /* 適応度の計算 */ /****************/ void Adap() { max = 0.0; max_n = -1; mean = 0.0; int n = 0; for (int i1 = 0; i1 < size+max_ch; i1++) { if (pi_w[i1] == 1) { double x = 0.0; double y = 0.0; for (int i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += Math.Pow(2.0, y); y += 1.0; } x *= cv; pi[i1] = Math.Sin(3.0*x) + 0.5 * Math.Sin(9.0*x) + Math.Sin(15.0*x+50.0); pi_w[i1] = 2; } if (pi_w[i1] > 0) { mean += pi[i1]; n++; if (max_n < 0 || pi[i1] > max) { max = pi[i1]; max_n = i1; } } } mean /= n; } /*****************************/ /* 結果の出力 */ /* gen : 現在の世代番号 */ /*****************************/ void Output(int gen) { int pr = -1; if (out_lvl >= 0) { Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "); pr = int.Parse(Console.ReadLine()); } if (pr != 0) { StreamWriter OUT = new StreamWriter(o_file, true); // 出力先の決定と評価値の出力 if (pr < 0) { DateTime now = DateTime.Now; // 現在時刻の獲得 OUT.WriteLine("***世代 " + gen + " 適応度 max " + max + " (" + max_n + ") mean " + mean + " 時間 " + now); } // 詳細出力 int k = 0; for (int i1 = 0; i1 < size+max_ch; i1++) { if ((pi_w[i1] > 1) && (out_m ==0 || out_m == 1 && i1 == max_n)) { if (pr < 0) { OUT.Write(i1 + " allele"); for (int i2 = 0; i2 < len[i1]; i2++) OUT.Write(" " + ind[i1][i2]); double x = 0.0; double y = 0.0; for (int i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += Math.Pow(2.0, y); y += 1.0; } x *= cv; OUT.WriteLine(" x " + x + " y " + pi[i1]); } else { Console.Write(i1 + " allele"); for (int i2 = 0; i2 < len[i1]; i2++) Console.Write(" " + ind[i1][i2]); double x = 0.0; double y = 0.0; for (int i2 = len[i1]-1; i2 >= 0; i2--) { if (ind[i1][i2] > 0) x += Math.Pow(2.0, y); y += 1.0; } x *= cv; Console.WriteLine(" x " + x + " y " + pi[i1]); } if (pr > 0) { k++; if (k == pr) { Console.ReadLine(); k = 0; } } } } OUT.Close(); } } } /****************/ /* main program */ /****************/ class Program { static void Main(String[] args) { // 入力ミス if (args.Length == 0) Console.WriteLine("***error ケーススタディファイル名を入力して下さい\n"); // 入力OK else { // 入力データファイル名の入力 String[] lines = File.ReadAllLines(args[0]); int n = int.Parse(lines[0]); // 問題の数 String[] i_file1 = new String [n]; String[] i_file2 = new String [n]; char[] charSep = new char[] {' '}; for (int i1 = 0; i1 < n; i1++) { string[] str = lines[i1+1].Split(charSep, StringSplitOptions.RemoveEmptyEntries); i_file1[i1] = str[0]; i_file2[i1] = str[1]; } // 実行(乱数の初期値を変える) for (int i1 = 0; i1 < n; i1++) { Console.WriteLine(); Console.WriteLine("+++++ケース " + (i1+1) + "+++++\n"); // 入力と初期設定 Function fn = new Function (i_file1[i1], i_file2[i1], 1000 * i1 + 1234567); // 最適化 fn.Control(); } } } } //------------------ケーススタディデータ(data_cf.txt)------ /* 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt */ //------------------Species記述データ(data1_f.txt)--------- /* 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 */ //------------------Function記述データ(data2_f.txt)-------- /* 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 */
'*********************************' ' 遺伝的アルゴリズムによるTSPの解 ' ' coded by Y.Suganuma ' '*********************************' Imports System.IO Imports System.Text.RegularExpressions Module Test Sub Main(args() As String) ' 入力ミス If args.Length = 0 Console.WriteLine("***error ケーススタディファイル名を入力して下さい") ' 入力OK Else ' 入力データファイル名の入力 Dim inp As StreamReader = New StreamReader(args(0)) Dim MS As Regex = New Regex("\s+") Dim n As Integer = Integer.Parse(inp.ReadLine().Trim()) ' 問題の数 Dim i_file1(n) As String Dim i_file2(n) As String For i1 As Integer = 0 To n-1 Dim str() As String = MS.Split(inp.ReadLine().Trim()) i_file1(i1) = str(0) i_file2(i1) = str(1) Next inp.Close() ' 実行(乱数の初期値を変える) For i1 As Integer = 0 To n-1 Console.WriteLine() Console.WriteLine("+++++ケース " & (i1+1) & "+++++") ' 入力と初期設定 Dim tsp As TSP = new TSP (i_file1(i1), i_file2(i1), 1000 * i1 + 1234567) ' 最適化 tsp.Control() Next End If End Sub '*********************' ' クラスSpeciesの定義 ' '*********************' Class Species protected max As Double ' 最大適応度 protected mean As Double ' 平均適応度 protected pi() As Double ' 適応度 protected ro() As Double ' ルーレット板 protected allele_u As Integer ' 対立遺伝子上限 protected allele_l As Integer ' 対立遺伝子下限 protected size As Integer ' 個体総数 protected max_ch As Integer ' 子供の数の最大値 protected max_len As Integer ' 最大遺伝子長 protected min_len As Integer ' 最小遺伝子長(負の時は,最大遺伝子長で固定) protected max_n As Integer ' 最大適応度の個体番号 protected dup_a As Integer ' 遺伝子の重複 ' =0 : 重複を許さない ' =1 : 重複を許す protected dup_s As Integer ' 個体の重複(同じ染色体の個体) ' =0 : 重複を許さない ' =1 : 重複を許す protected ind(,) As Integer ' 集団(個体の集まり) protected len() As Integer ' 各個体の遺伝子長 protected kou1() As Integer ' 交叉・突然変異用作業場所1 protected kou2() As Integer ' 交叉・突然変異用作業場所2 protected s_w() As Integer ' 淘汰用指標(選択された回数) protected edge(,) As Integer ' エッジ組み替え交叉用ワークエリア protected pi_w() As Integer ' 適応度計算指標 ' =0 : 未使用 ' =1 : 適応度計算前(突然変異はこの個体だけに適用) ' =2 : 適応度計算済み(交叉時に親とみなす) protected rn As Random ' 乱数 '**************************' ' コンストラクタ ' ' name : ファイル名 ' ' seed : 乱数の初期値 ' '**************************' Public Sub New (name As String, seed As Integer) Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name) ' ' データの入力 ' ' 1行目 Dim str() As String = MS.Split(inp.ReadLine().Trim()) allele_u = Integer.Parse(str(1)) allele_l = Integer.Parse(str(3)) ' 2行目 str = MS.Split(inp.ReadLine().Trim()) max_len = Integer.Parse(str(1)) min_len = Integer.Parse(str(3)) ' 3行目 str = MS.Split(inp.ReadLine().Trim()) dup_a = Integer.Parse(str(1)) dup_s = Integer.Parse(str(3)) ' 4行目 str = MS.Split(inp.ReadLine().Trim()) size = Integer.Parse(str(1)) max_ch = Integer.Parse(str(3)) inp.Close() ' ' データのチェック ' If size <= 0 Console.WriteLine("***error 個体総数≦0 (Constructor)") Environment.Exit(1) End If If max_ch < 0 Console.WriteLine("***error 子供の数<0 (Constructor)") Environment.Exit(1) End If If max_len <= 0 or min_len = 0 Console.WriteLine("***error 遺伝子長≦0 (Constructor)") Environment.Exit(1) End If If max_len < min_len Console.WriteLine("***error 最大遺伝子長<最小遺伝子長 (Constructor)") Environment.Exit(1) End If If allele_u <= allele_l Console.WriteLine("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)") Environment.Exit(1) End If Dim kind As Integer = allele_u - allele_l + 1 If dup_a = 0 and max_len > kind Console.WriteLine("***error 遺伝子の重複を防ぐことはできない (Constructor)") Environment.Exit(1) End If ' ' 領域の確保 ' Dim num As Integer = size + max_ch ReDim ind(num, max_len) ReDim edge(max_len, 5) ReDim pi(num) ReDim ro(num) ReDim len(num) ReDim kou1(max_len) ReDim kou2(max_len) ReDim s_w(num) ReDim pi_w(num) ' ' 乱数の初期設定 ' rn = new Random(seed) End Sub '*********************************' ' 正規分布変量の発生 ' ' m : 平均 ' ' s : 標準偏差 ' ' return : 正規分布変量 ' '*********************************' Function norm_d(m As Double, s As Double) Dim x As Double = 0.0 For i1 As Integer = 0 To 11 x += rn.NextDouble() Next x = s * (x - 6.0) + m Return x End Function '************************************************' ' 場所を探す ' ' n : >=0 : n番目の親を捜す ' ' -1 : 空いている場所を探す ' ' return : 親の場所,または,空いている場所 ' ' (存在しないときは負の値) ' '************************************************' Function Position(n As Integer) Dim i1 As Integer Dim k As Integer = -1 Dim sw As Integer = 0 ' ' 空いている場所を探す ' If n < 0 i1 = 0 Do While i1 < size+max_ch and k < 0 If pi_w(i1) = 0 k = i1 End If i1 += 1 Loop If k < 0 Console.WriteLine("***error 空いている場所がない --Position--") Environment.Exit(1) End If ' ' n番目の親(pi_w(i)=2)を捜す ' Else i1 = 0 Do While i1 < size+max_ch and sw = 0 If pi_w(i1) = 2 k += 1 If k = n sw = 1 k = i1 End If End If i1 += 1 Loop End If Return k End Function '*****************************************************************' ' 個体の選択 ' ' method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' bias : α,または,method=2の場合は初期値 ' ' sttp : β ' ' return : 個体番号 ' '*****************************************************************' Function Select_f(method As Integer, bias As Double, sttp As Double) Dim sum As Double = 0.0 Dim x As Double Dim i1 As Integer Dim k As Integer Dim min As Integer Dim n As Integer Dim sw As Integer ' ルーレット板の用意 Select Case method ' ランダム Case -1 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 n += 1 End If Next sum = 1.0 / n For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = sum End If Next ' 評価値をそのまま利用 Case 0 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 sum += pi(i1) n += 1 End If Next If Math.Abs(sum) > 1.0e-10 sum = 1.0 / Math.Abs(sum) For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = pi(i1) * sum End If Next Else sum = 1.0 / n For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = sum End If Next End If ' 最小値からの差 Case 1 min = -1 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 n += 1 If min < 0 min = i1 ElseIf pi(i1) < pi(min) min = i1 End If End If Next For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = pi(i1) - pi(min) If ro(i1) < bias ro(i1) = bias End If sum += ro(i1) End If Next If sum > 1.0e-10 sum = 1.0 / sum For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) *= sum End If Next Else sum = 1.0 / n For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = sum End If Next End If ' 線形化 Case 2 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = -1.0 n += 1 Else ro(i1) = 1.0 End If Next sw = 0 sum = bias Do while sw = 0 min = -1 For i1 = 0 To size+max_ch-1 If ro(i1) < 0.0 If min < 0 min = i1 ElseIf pi(i1) < pi(min) min = i1 End If End If Next If min < 0 sw = 1 Else ro(min) = sum sum += sttp End If Loop sum = 1.0 / (0.5 * (2.0 * bias + sttp * (n - 1)) * n) For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) *= sum End If Next End Select sum = 0.0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 sum += ro(i1) ro(i1) = sum End If Next ' 選択 x = rn.NextDouble() sw = 0 k = 0 i1 = 0 Do While i1 < size+max_ch and sw = 0 If pi_w(i1) > 1 If x <= ro(i1) sw = 1 k = i1 End If End If i1 += 1 Loop Return k End Function '******************' ' 標準的な初期設定 ' '******************' Sub Init_std() Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim length As Integer Dim lid As Integer Dim sw1 As Integer Dim sw2 As Integer ' ' 初期設定 ' For i1 = 0 To size+max_ch-1 If i1 < size pi_w(i1) = 1 ' 適応度の計算前 Else pi_w(i1) = 0 ' 未使用 End If Next ' ' 遺伝子の決定 ' For i1 = 0 To size-1 sw1 = 0 Do While sw1 = 0 ' 遺伝子長の決定 If min_len < 0 length = max_len Else length = Math.Floor(rn.NextDouble() * (max_len - min_len + 1) + min_len) If length > max_len length = max_len End If End If len(i1) = length ' 遺伝子の決定 For i2 = 0 To length-1 sw2 = 0 Do While sw2 = 0 lid = Math.Floor(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l) If lid > allele_u lid = allele_u End If ind(i1,i2) = lid ' 重複遺伝子のチェック sw2 = 1 If dup_a = 0 i3 = 0 Do While i3 < i2 and sw2 > 0 If lid = ind(i1,i3) sw2 = 0 End If i3 += 1 Loop End If Loop Next ' 重複個体のチェック sw1 = 1 If dup_s = 0 i2 = 0 Do While i2 < i1 and sw1 > 0 If len(i1) = len(i2) sw2 = 0 i3 = 0 Do While i3 < len(i1) and sw2 = 0 If ind(i1,i3) <> ind(i2,i3) sw2 = 1 End If i3 += 1 Loop If sw2 = 0 sw1 = 0 End If End If i2 += 1 Loop End If Loop Next End Sub '**************************************************' ' 標準的な出力 ' ' sw : 出力レベル ' ' =0 : 最終出力だけ ' ' n>0 : n世代毎に出力(負はファイル) ' ' out_m : 出力方法 ' ' =0 : すべての個体を出力 ' ' =1 : 最大適応度の個体だけを出力 ' ' gen : 現在の世代番号 ' ' name : 出力ファイル名 ' '**************************************************' Sub Out_std(sw As Integer, out_m As Integer, gen As Integer, name As String) Dim pr As Integer = -1 If sw >= 0 Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer.Parse(Console.ReadLine()) End If If pr <> 0 Dim OUT As StreamWriter = new StreamWriter(name, true) ' 出力先の決定と評価値の出力 If pr < 0 Dim now1 As DateTime = DateTime.Now ' 現在時刻の獲得 OUT.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean & " 時間 " & now1) End If ' 詳細出力 Dim k As Integer = 0 For i1 As Integer = 0 To size+max_ch-1 If (pi_w(i1) > 1) and (out_m = 0 or out_m = 1 and i1 = max_n) If pr < 0 OUT.Write(i1 & " allele") For i2 As Integer = 0 To len(i1)-1 OUT.Write(" " & ind(i1,i2)) Next OUT.WriteLine(" value " & pi(i1)) Else Console.Write(i1 & " allele") For i2 As Integer = 0 To len(i1)-1 Console.Write(" " & ind(i1,i2)) Next Console.WriteLine(" value " & pi(i1)) End If If pr > 0 k += 1 If k = pr Console.ReadLine() k = 0 End If End If End If Next OUT.Close() End If End Sub '*****************************************************************' ' 交叉(親のコピー) ' ' method : =2 : 有性(2つの親から2つの子供) ' ' =1 : 1つの親から1つの子供 ' ' pair : method=2 の時は親のペア数 ' ' method=1 の時は親の数(=子供の数) ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_copy(method As Integer, pair As Integer, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータチェック ' If method <> 1 method = 2 End If If pair <= 0 If method = 2 pair = max_ch / 2 Else pair = max_ch End If Else If method = 2 and 2*pair > max_ch or method = 1 and pair > max_ch Console.WriteLine("***error 子供が多すぎる (C_copy)") Environment.Exit(1) End If End If ' ' 実行 ' For i1 = 0 To pair-1 ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do while sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' コピー For i2 = 0 To method-1 If i2 = 0 p = p1 Else p = p2 End If k = Position(-1) len(k) = len(p) pi_w(k) = 1 For i3 = 0 To len(k)-1 ind(k,i3) = ind(p,i3) Next Next Next End Sub '*****************************************************************' ' 交叉(多点交叉) ' ' kosa : 交叉確率 ' ' k_point : 交叉点の数 ' ' (負の時は,1から-k_point間のランダム) ' ' k_vr : =0 : 両親とも同じ位置で交叉 ' ' =1 : 両親が異なる位置で交叉(遺伝子長は可変) ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_point(kosa As Double, k_point As Integer, k_vr As Integer, k_method As Integer, k_bias As Double, k_step As Double) Dim abs_p As Integer Dim c1 As Integer Dim c2 As Integer Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim mn As Integer = 0 Dim num As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim pair As Integer Dim sw As Integer Dim t11 As Integer Dim t12 As Integer Dim t21 As Integer Dim t22 As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a = 0 Console.WriteLine("***error 交叉方法が不適当 (C_point)") Environment.Exit(1) End If abs_p = Math.Abs(k_point) If abs_p = 0 or abs_p > max_len-1 or min_len > 0 and abs_p > min_len-1 Console.WriteLine("***error 交叉点の数が不適当 (C_point)") Environment.Exit(1) End If If k_vr > 0 and min_len < 0 Console.WriteLine("***error 遺伝子長は可変でなければならない (C_point)") Environment.Exit(1) End If ' ' 交叉 ' num = k_point For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 交叉位置の数の決定 If k_point < 0 num = Math.Floor(rn.NextDouble() * abs_p + 1) If num > abs_p num = abs_p End If End If ' 交叉位置の決定(点の後ろで交叉) For i2 = 0 To num-1 ' 親1の交叉位置 sw = 0 Do While sw = 0 sw = 1 kou1(i2) = Math.Floor(rn.NextDouble() * (len(p1) - 1)) If kou1(i2) > len(p1)-2 kou1(i2) = len(p1) - 2 End If If k_vr = 0 and kou1(i2) > len(p2)-2 kou1(i2) = len(p2) - 2 End If i3 = 0 Do While i3 < i2 and sw > 0 If kou1(i3) = kou1(i2) sw = 0 End If i3 += 1 Loop Loop ' 親2の交叉位置 If k_vr > 0 sw = 0 Do While sw = 0 sw = 1 kou2(i2) = Math.Floor(rn.NextDouble() * (len(p2) - 1)) If kou2(i2) > len(p2)-2 kou2(i2) = len(p2) - 2 End If i3 = 0 Do While i3 < i2 and sw > 0 If kou2(i3) = kou2(i2) sw = 0 End If i3 += 1 Loop Loop End If Next ' 交叉の実行 ' 親1のt11からt12を子1のc1へコピー ' 親2のt21からt22を子2のc2へコピー ' 次は, ' 親1のt11からt12を子2のc2へコピー ' 親2のt21からt22を子1のc1へコピー ' ・・・・・ c1 = 0 c2 = 0 t11 = 0 t21 = 0 ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) For i2 = 0 To num ' 次の交叉位置を求める If i2 = num ' 最後 t12 = len(p1) t22 = len(p2) Else ' 親1 t12 = max_len For i3 = 0 To num-1 If kou1(i3) >= 0 and kou1(i3) <= t12 t12 = kou1(i3) mn = i3 End If Next kou1(mn) = -1 t12 += 1 ' 親2 If k_vr = 0 t22 = t12 Else t22 = max_len For i3 = 0 To num-1 If kou2(i3) >= 0 and kou2(i3) <= t22 t22 = kou2(i3) mn = i3 End If Next kou2(mn) = -1 t22 += 1 End If End If ' 指定箇所のコピー For i3 = t11 To t12-1 If (i2 Mod 2) = 0 If c1 < max_len ind(k1,c1) = ind(p1,i3) c1 += 1 End If Else If c2 < max_len ind(k2,c2) = ind(p1,i3) c2 += 1 End If End If Next For i3 = t21 To t22-1 If (i2 Mod 2) = 0 If c2 < max_len ind(k2,c2) = ind(p2,i3) c2 += 1 End If Else If c1 < max_len ind(k1,c1) = ind(p2,i3) c1 += 1 End If End If Next ' 交叉位置の移動 t11 = t12 t21 = t22 Next End If Next End Sub '*****************************************************************' ' 交叉(一様交叉.(0,1)を等確率で発生させ,1であれば, ' ' 親1,0であれば親2の遺伝子を子1が受け継ぐ) ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_uniform(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim k1 As Integer Dim k2 As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim pair As Integer Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a = 0 Console.WriteLine("***error 交叉方法が不適当 (C_unIForm)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_unIForm)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 For i2 = 0 To len(p1)-1 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) End If Next End If Next End Sub '*****************************************************************' ' 交叉(平均化交叉.2つの親の平均値を受け継ぐ) ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_mean(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim k As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_mean)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To max_ch-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(1, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k = Position(-1) len(k) = len(p1) pi_w(k) = 1 ' 交叉 For i2 = 0 To len(k)-1 ind(k,i2) = (ind(p1,i2) + ind(p2,i2)) / 2 Next End If Next End Sub '*****************************************************************' ' 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を ' ' そのまま各子供が選択する.その位置にある親2(1)の遺伝 ' ' 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 ' ' ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 ' ' 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り ' ' 返し,残りの遺伝子については,子1(2)は,親2(1)の ' ' 遺伝子をその順番通りに受け継ぐ) ' ' 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 ' ' * → → ' ' 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_cycle(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_cycle)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_cycle)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 初期設定 For i2 = 0 To len(p1)-1 kou1(i2) = 0 kou2(i2) = 0 Next ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 sw = 0 Do While sw = 0 sw = 1 p = Math.Floor(rn.NextDouble() * len(p1)) If p >= len(p1) p = len(p1) - 1 End If If kou1(p) = 0 and kou2(p) = 0 kou1(p) = 1 kou2(p) = 1 ind(k1,p) = ind(p1,p) ind(k2,p) = ind(p2,p) i2 = 0 Do While i2 < len(p1) and sw > 0 If ind(p2,p) = ind(p1,i2) ind(k1,i2) = ind(p1,i2) kou1(i2) = 1 sw = 0 End If i2 += 1 Loop sw = 1 i2 = 0 Do While i2 < len(p2) and sw > 0 If ind(p1,p) = ind(p2,i2) ind(k2,i2) = ind(p2,i2) kou2(i2) = 1 sw = 0 End If i2 += 1 Loop End If Loop sw = 0 i2 = 0 i3 = 0 Do While sw = 0 Do While sw = 0 and i2 < len(p1) If kou1(i2) = 0 sw = 1 Else i2 += 1 End If Loop sw = 0 Do While sw = 0 and i3 < len(p2) If kou2(i3) = 0 sw = 1 Else i3 += 1 End If Loop If i2 < len(p1) and i3 < len(p2) ind(k1,i2) = ind(p2,i3) ind(k2,i3) = ind(p1,i2) sw = 0 i2 += 1 i3 += 1 Else sw = 1 End If Loop End If Next End Sub '*****************************************************************' ' 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と ' ' 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ ' ' の2つの遺伝子の位置を交換する.この操作を,選択した点よ ' ' り右にあるすべての遺伝子に対して実施する ' ' 2 4 1 3 6 5 2 4 5 3 6 1 ' ' * → → ・・・・・ ' ' 3 2 5 4 1 6 3 2 1 4 5 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_part(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim lv As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_part)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_part)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 p = Math.Floor(rn.NextDouble() * len(p1)) If p >= len(p1) p = len(p1) - 1 End If For i2 = 0 To len(p1)-1 ind(k1,i2) = ind(p1,i2) ind(k2,i2) = ind(p2,i2) Next For i2 = p To len(p1)-1 sw = 0 lv = ind(k1,i2) i3 = 0 Do While i3 < len(p1) and sw = 0 If ind(k2,i2) = ind(k1,i3) ind(k1,i2) = ind(k1,i3) ind(k1,i3) = lv sw = 1 End If i3 += 1 Loop sw = 0 i3 = 0 Do While i3 < len(p1) and sw = 0 If lv = ind(k2,i3) ind(k2,i3) = ind(k2,i2) ind(k2,i2) = lv sw = 1 End If i3 += 1 Loop Next End If Next End Sub '*****************************************************************' ' 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の ' ' 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 ' ' の遺伝子を親2の遺伝子の出現順序に並べ替える. ' ' 2 4 1 3 6 5 2 4 1 3 5 6 ' ' * → ' ' 3 2 5 4 1 6 3 2 5 4 1 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_seq(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim pp As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_seq)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_seq)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 p = Math.Floor(rn.NextDouble() * (len(p1) - 1)) If p >= len(p1)-1 p = len(p1) - 2 End If For i2 = 0 To p ind(k1,i2) = ind(p1,i2) ind(k2,i2) = ind(p2,i2) Next pp = 0 For i2 = p+1 To len(p1)-1 sw = 0 i3 = pp Do While i3 < len(p2) and sw = 0 i4 = p + 1 Do While i4 < len(p1) and sw = 0 If ind(p2,i3) = ind(p1,i4) sw = 1 pp = i3 + 1 ind(k1,i2) = ind(p1,i4) End If i4 += 1 Loop i3 += 1 Loop Next pp = 0 For i2 = p+1 To len(p2)-1 sw = 0 i3 = pp Do While i3 < len(p1) and sw = 0 i4 = p + 1 Do While i4 < len(p2) and sw = 0 If ind(p1,i3) = ind(p2,i4) sw = 1 pp = i3 + 1 ind(k2,i2) = ind(p2,i4) End If i4 += 1 Loop i3 += 1 Loop Next End If Next End Sub '*****************************************************************' ' 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 ' ' 択された位置における遺伝子の順序に従って,他の親の遺伝子 ' ' を並べ替える ' ' 2 4 1 3 6 5 2 4 1 3 6 5 ' ' * * → ' ' 3 2 5 4 1 6 4 2 5 3 1 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_useq(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_useq)\n") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_useq)\n") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 For i2 = 0 To len(p1)-1 ind(k1,i2) = ind(p1,i2) ind(k2,i2) = ind(p2,i2) If rn.NextDouble() < 0.5 kou1(i2) = 0 Else kou1(i2) = 1 End If Next p = 0 For i2 = 0 To len(p1)-1 If kou1(i2) > 0 sw = 0 i3 = p Do While i3 < len(p2) and sw = 0 i4 = 0 Do While i4 < len(p1) and sw = 0 If ind(p2,i3) = ind(p1,i4) and kou1(i4) > 0 sw = 1 p = i3 + 1 ind(k1,i2) = ind(p1,i4) End If i4 += 1 Loop i3 += 1 Loop End If Next p = 0 For i2 = 0 To len(p2)-1 If kou1(i2) > 0 sw = 0 i3 = p Do While i3 < len(p1) and sw = 0 i4 = 0 Do While i4 < len(p2) and sw = 0 If ind(p1,i3) = ind(p2,i4) and kou1(i4) > 0 sw = 1 p = i3 + 1 ind(k2,i2) = ind(p2,i4) End If i4 += 1 Loop i3 += 1 Loop End If Next End If Next End Sub '*****************************************************************' ' 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 ' ' 択された位置における遺伝子の位置に,他の親の同じ遺伝子を ' ' 配置する.残りの遺伝子は,親と同じ順序に配置する. ' ' 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 ' ' * * → → ' ' 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_upos(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_upos)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_upos)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 For i2 = 0 To len(p1)-1 If rn.NextDouble() < 0.5 kou1(i2) = 0 Else kou1(i2) = 1 End If If kou1(i2) > 0 ind(k1,i2) = ind(p2,i2) ind(k2,i2) = ind(p1,i2) End If Next p = 0 For i2 = 0 To len(p1)-1 sw = 0 i3 = 0 Do While i3 < len(p1) and sw = 0 If kou1(i3) > 0 and ind(p1,i2) = ind(k1,i3) sw = 1 End If i3 += 1 Loop If sw = 0 i3 = p Do While i3 < len(p1) and sw = 0 If kou1(i3) = 0 ind(k1,i3) = ind(p1,i2) p = i3 + 1 sw = 1 End If i3 += 1 Loop End If Next p = 0 For i2 = 0 To len(p2)-1 sw = 0 i3 = 0 Do While i3 < len(p2) and sw = 0 If kou1(i3) > 0 and ind(p2,i2) = ind(k2,i3) sw = 1 End If i3 += 1 Loop If sw = 0 i3 = p Do While i3 < len(p2) and sw = 0 If kou1(i3) = 0 ind(k2,i3) = ind(p2,i2) p = i3 + 1 sw = 1 End If i3 += 1 Loop End If Next End If Next End Sub '*****************************************************************' ' 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は ' ' 0~(max_len-1)である必要がある) ' ' (0) エッジマップを作成する.エッジマップとは,2つの親 ' ' を見て,ノードがどこに接続されているのかを表すもの ' ' であり,例えば,2つの親が, ' ' (A B C D E F) ' ' (B D C A E F) ' ' である場合は, ' ' A : B F C E ' ' B : A C D F ' ' C : B D A ' ' D : C E B ' ' E : D F A ' ' F : A E B ' ' となる. ' ' (1) 両親の2つの出発点の内1つで初期化する.ランダムま ' ' たはステップ(4)の基準に従って選ぶ(現在のノード) ' ' (2) エッジマップから,現在のノードを除く ' ' (3) 現在のノードが接続先のノードを持っていたら,(4)に ' ' 進む.さもなければ,(5)に進む ' ' (4) 現在のノードが持っている接続先ノードの内,最も少な ' ' い接続先ノードを持ったノードを選択し(同じ条件の場 ' ' 合は,ランダム),それを現在のノードとし,(2)に進む ' ' (5) 未接続のノードが残っていればランダムに選択し,(2)に ' ' 戻る.さもなければ,終了する ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_edge(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim i5 As Integer Dim k As Integer Dim kk As Integer Dim k0 As Integer = 0 Dim k1 As Integer Dim k2 As Integer Dim min As Integer Dim num As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer Dim e(2) As Integer ' ' 初期設定とデータのチェック ' pair = max_ch If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_edge)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_edge)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(1, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k = Position(-1) pi_w(k) = 1 len(k) = len(p1) ' エッジマップの初期化 For i2 = 0 To len(k)-1 edge(i2,0) = 0 For i3 = 1 To 4 edge(i2,i3) = -1 Next Next ' 交叉 ' エッジマップの作成 For i2 = 0 To len(k)-1 sw = 0 i3 = 0 Do While i3 < len(k) and sw = 0 If i2 = ind(p1,i3) sw = 1 If i3 = 0 e(0) = ind(p1,len(k)-1) e(1) = ind(p1,1) Else If i3 = len(k)-1 e(0) = ind(p1,i3-1) e(1) = ind(p1,0) Else e(0) = ind(p1,i3-1) e(1) = ind(p1,i3+1) End If End If For i4 = 0 To 1 edge(i2,0) += 1 edge(i2,edge(i2,0)) = e(i4) Next End If i3 += 1 Loop sw = 0 i3 = 0 Do While i3 < len(k) and sw = 0 If i2 = ind(p2,i3) sw = 1 If i3 = 0 e(0) = ind(p2,len(k)-1) e(1) = ind(p2,1) Else If i3 = len(k)-1 e(0) = ind(p2,i3-1) e(1) = ind(p2,0) Else e(0) = ind(p2,i3-1) e(1) = ind(p2,i3+1) End If End If For i4 = 0 To 1 sw = 1 i5 = 1 Do While i5 <= edge(i2,0) and sw = 1 If edge(i2,i5) = e(i4) sw = 2 End If i5 += 1 Loop If sw = 1 edge(i2,0) += 1 edge(i2,edge(i2,0)) = e(i4) End If Next End If i3 += 1 Loop Next ' 交叉の実行 ' 出発点の決定 k1 = ind(p1,0) k2 = ind(p2,0) If edge(k1,0) = edge(k2,0) If rn.NextDouble() > 0.5 kk = k2 Else kk = k1 End If Else If edge(k1,0) < edge(k2,0) kk = k1 Else kk = k2 End If End If ind(k,0) = kk p = 1 Do While p < len(k) ' ノードの除去 For i2 = 0 To len(k)-1 sw = 0 If edge(i2,0) > 0 i3 = 1 Do While i3 <= 4 and sw = 0 If edge(i2,i3) = kk sw = 1 edge(i2,i3) = -1 edge(i2,0) -= 1 End If i3 += 1 Loop End If Next ' 次の現在ノードの選択 min = 10 num = 0 For i2 = 1 To 4 If edge(kk,i2) >= 0 k1 = edge(kk,i2) If edge(k1,0) >= 0 and edge(k1,0) < min num = 1 min = edge(k1,0) k0 = k1 Else If edge(k1,0) = min num += 1 End If End If End If Next If num > 1 k1 = Math.Floor(rn.NextDouble() * num) + 1 If k1 > num k1 = num End If k2 = 0 k0 = -1 i2 = 1 Do While i2 <= 4 and k0 < 0 If edge(kk,i2) >= 0 If edge(edge(kk,i2),0) = min k2 += 1 If k1 = k2 k0 = edge(kk,i2) End If End If End If i2 += 1 Loop Else If num <= 0 num = 0 For i2 = 0 To len(k)-1 If i2 <> kk and edge(i2,0) >= 0 num += 1 End If Next If num <= 0 Console.WriteLine("***error invalid data (C_edge)") Environment.Exit(1) Else k1 = Math.Floor(rn.NextDouble() * num) + 1 If k1 > num k1 = num End If k2 = 0 k0 = -1 i2 = 0 Do While i2 < len(k) and k0 < 0 If i2 <> kk and edge(i2,0) >= 0 k2 += 1 If k1 = k2 k0 = i2 End If End If i2 += 1 Loop End If End If End If edge(kk,0) = -1 ind(k,p) = k0 kk = k0 p += 1 Loop End If Next End Sub '***********************************************************' ' 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に' ' 同じ遺伝子のグループがない限り実行されない.たとえば' ' ***abcd** ' ' *cdab**** ' ' のような両親の時実行され,以下の4つの子供が生成され' ' る) ' ' ***cdab** ' ' *abcd**** ' ' ***badc** ' ' *dcba**** ' ' 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 ' ' 供が生成される可能性があるので,子供の数としてこの値' ' 以上のデータを入力しておく必要がある. ' ' kosa : 交叉確率 ' ' count : 1つのペアーに対する交差回数 ' '***********************************************************' Sub C_sub(kosa As Double, count As Integer) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim i5 As Integer Dim k1 As Integer Dim k2 As Integer Dim k3 As Integer Dim k4 As Integer Dim p1 As Integer Dim p2 As Integer Dim t11 As Integer Dim t12 As Integer = 0 Dim t21 As Integer Dim t22 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' If (4*count*size*(size-1)) > max_ch Console.WriteLine("***error 子供が多すぎる (C_sub)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To size-2 ' 親1 p1 = Position(i1) If p1 >= 0 For i2 = i1 To size-1 ' 親2 p2 = Position(i2) If p2 >= 0 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 交叉回数の制御 For i3 = 0 To count-1 ' 交叉位置の決定(点の後ろで交叉) ' 親1の交叉位置 t11 = Math.Floor(rn.NextDouble() * len(p1)) If t11 > (len(p1)-1) t11 = len(p1) - 1 End If sw = 0 Do While sw = 0 t12 = Math.Floor(rn.NextDouble() * len(p1)) If t12 > (len(p1)-1) t12 = len(p1) - 1 End If If t12 <> t11 sw = 1 End If Loop If t11 > t12 k1 = t11 t11 = t12 t12 = k1 End If ' 親2の交叉位置 sw = 0 t21 = -1 i4 = 0 Do While i4 < len(p2) and t21 < 0 i5 = t11 Do While i5 <= t12 and t21 < 0 If ind(p2,i4) = ind(p1,i5) t21 = i4 End If i5 += 1 Loop i4 += 1 Loop If t21 >= 0 t22 = t21 + t12 - t11 If t22 < len(p2) sw = 1 i4 = t21 + 1 Do While i4 <= t22 and sw > 0 sw = 0 i5 = t11 Do While i5 <= t12 and sw = 0 If ind(p2,i4) = ind(p1,i5) sw = 1 End If i5 += 1 Loop i4 += 1 Loop End If End If ' 交叉の実行 If sw > 0 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p1) k3 = Position(-1) pi_w(k3) = 1 len(k3) = len(p2) k4 = Position(-1) pi_w(k4) = 1 len(k4) = len(p2) For i4 = 0 To t11-1 ind(k1,i4) = ind(p1,i4) ind(k2,i4) = ind(p1,i4) Next For i4 = t11 To t12 ind(k1,i4) = ind(p2,t21+i4-t11) ind(k2,i4) = ind(p2,t22-i4+t11) Next For i4 = t12+1 To len(p1)-1 ind(k1,i4) = ind(p1,i4) ind(k2,i4) = ind(p1,i4) Next For i4 = 0 To t21-1 ind(k3,i4) = ind(p2,i4) ind(k4,i4) = ind(p2,i4) Next For i4 = t21 To t22 ind(k3,i4) = ind(p1,t11+i4-t21) ind(k4,i4) = ind(p1,t12-i4+t21) Next For i4 = t22+1 To len(p2)-1 ind(k3,i4) = ind(p2,i4) ind(k4,i4) = ind(p2,i4) Next End If Next End If End If Next End If Next End Sub '************************************' ' 突然変異(対立遺伝子との置き換え) ' ' pr : 突然変異率 ' '************************************' Sub M_alle(pr As Double) Dim i1 As Integer Dim i2 As Integer Dim lid As Integer ' ' データのチェックと初期設定 ' If dup_a = 0 Console.WriteLine("***error 突然変異方法が不適当 (M_alle)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 For i2 = 0 To len(i1)-1 If rn.NextDouble() <= pr lid = Math.Floor(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l) If lid > allele_u lid = allele_u End If If lid <> ind(i1,i2) ind(i1,i2) = lid End If End If Next End If Next End Sub '********************************************************************' ' 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に ' ' 移動する) ' ' pr : 突然変異率 ' '********************************************************************' Sub M_move(pr As Double) Dim i1 As Integer Dim i2 As Integer Dim ld As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 位置の決定 ' ' p1 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If ' p2 sw = 0 Do While sw = 0 p2 = Math.Floor(rn.NextDouble() * len(i1)) If p2 >= len(i1) p2 = len(i1) - 1 End If If p2 <> p1 sw = 1 End If Loop ' ' 実行 ' If p2 > p1 ld = ind(i1,p2) For i2 = p2 To p1+1 Step -1 ind(i1,i2) = ind(i1,i2-1) Next ind(i1,p1) = ld Else ld = ind(i1,p2) For i2 = p2 To p1-2 ind(i1,i2) = ind(i1,i2+1) Next ind(i1,p1-1) = ld End If End If Next End Sub '******************************************************' ' 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '******************************************************' Sub M_inv(pr As Double, wd As Integer) Dim i1 As Integer Dim lid As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 区間の決定 ' If wd = 0 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If sw = 0 Do While sw = 0 p2 = Math.Floor(rn.NextDouble() * len(i1)) If p2 >= len(i1) p2 = len(i1) - 1 End If If p2 <> p1 sw = 1 End If Loop If p1 > p2 p = p1 p1 = p2 p2 = p End If Else p1 = len(i1) Do While p1 > len(i1)-2 p1 = Math.Floor(rn.NextDouble() * len(i1)) Loop p2 = p1 + wd - 1 If p2 >= len(i1) p2 = len(i1) - 1 End If End If ' ' 実行 ' sw = 0 Do While sw = 0 lid = ind(i1,p1) ind(i1,p1) = ind(i1,p2) ind(i1,p2) = lid p1 += 1 p2 -= 1 If p1 >= p2 sw = 1 End If Loop End If Next End Sub '********************************************************************' ' 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_scram(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim ld As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 区間の決定 ' If wd = 0 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If sw = 0 Do While sw = 0 p2 = Math.Floor(rn.NextDouble() * len(i1)) If p2 >= len(i1) p2 = len(i1) - 1 End If If p2 <> p1 sw = 1 End If Loop If p1 > p2 p = p1 p1 = p2 p2 = p End If Else p1 = len(i1) Do While p1 > len(i1)-2 p1 = Math.Floor(rn.NextDouble() * len(i1)) Loop p2 = p1 + wd - 1 If p2 >= len(i1) p2 = len(i1) - 1 End If End If ' ' 実行 ' For i2 = p1 To p2 p = Math.Floor(rn.NextDouble() * (p2 - p1 + 1) + p1) If p > p2 p = p2 End If ld = ind(i1,i2) ind(i1,i2) = ind(i1,p) ind(i1,p) = ld Next End If Next End Sub '********************************************************************' ' 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし ' ' 重複部分はそのままとする) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_chg(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim ld As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer Dim p3 As Integer = 0 Dim p4 As Integer Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 区間等の決定((p1,p2)と(p3,p4)の入れ替え) ' ' p1 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If ' p3 sw = 0 Do While sw = 0 p3 = Math.Floor(rn.NextDouble() * len(i1)) If p3 >= len(i1) p3 = len(i1) - 1 End If If p3 <> p1 sw = 1 End If Loop ' 小さい方をp1,p2にする If p1 > p3 p = p1 p1 = p3 p3 = p End If ' p4, p2 If wd = 0 p4 = Math.Floor(rn.NextDouble() * (len(i1) - p3)) + p3 Else p4 = p1 + wd - 1 End If If p4 >= len(i1) p4 = len(i1) - 1 End If p2 = p1 + (p4 - p3) ' 重複部分のチェック If p2 >= p3 p = p3 - 1 p3 = p2 + 1 p2 = p p4 = p3 + (p2 - p1) End If ' ' 実行 ' p = p3 For i2 = p1 To p2 ld = ind(i1,i2) ind(i1,i2) = ind(i1,p) ind(i1,p) = ld p += 1 Next End If Next End Sub '********************************************************************' ' 突然変異(重複.2点間の遺伝子を他の位置にコピーする ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_dup(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer Dim p3 As Integer = 0 Dim p4 As Integer Dim sw As Integer ' ' データのチェック ' If dup_a = 0 Console.WriteLine("***error 突然変異方法が不適当 (M_dup)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' 区間の決定((p1,p2)を(p3,p4)にコピー) ' p1 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If ' p3 sw = 0 Do While sw = 0 p3 = Math.Floor(rn.NextDouble() * len(i1)) If p3 >= len(i1) p3 = len(i1) - 1 End If If p3 <> p1 sw = 1 End If Loop ' 区間を決める If p3 > p1 If wd = 0 p4 = Math.Floor(rn.NextDouble() * (len(i1) - p3)) + p3 Else p4 = p3 + wd - 1 End If If p4 >= len(i1) p4 = len(i1) - 1 End If p2 = p1 + (p4 - p3) Else If wd = 0 p2 = Math.Floor(rn.NextDouble() * (len(i1) - p1)) + p1 Else p2 = p1 + wd - 1 End If If p2 >= len(i1) p2 = len(i1) - 1 End If p4 = p3 + (p2 - p1) End If ' 実行 p = p4 For i2 = p2 To p1 Step -1 ind(i1,p) = ind(i1,i2) p -= 1 Next End If Next End Sub '****************************************************' ' 突然変異(摂動.値をある量だけ変化させる) ' ' pr : 突然変異率 ' ' method : =0 : 正規分布 ' ' =1 : 一様分布 ' ' m : 平均または一様分布の下限 ' ' s : 標準偏差または一様分布の上限 ' '****************************************************' Sub M_per(pr As Double, method As Integer, m As Double, s As Double) Dim w As Double Dim wd As Double = 0.0 Dim x1 As Double Dim i1 As Integer Dim i2 As Integer ' ' データのチェックと初期設定 ' If dup_a = 0 Console.WriteLine("***error 突然変異方法が不適当 (M_per)") Environment.Exit(1) End If If method > 0 wd = s - m End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 For i2 = 0 To len(i1)-1 If rn.NextDouble() <= pr If method = 0 w = norm_d(m, s) Else w = rn.NextDouble() * wd If rn.NextDouble() < 0.5 w = -w End If End If x1 = ind(i1,i2) + w If x1 > allele_u x1 = allele_u Else If x1 < allele_l x1 = allele_l End If End If ind(i1,i2) = Math.Floor(x1) End If Next End If Next End Sub '********************************************************************' ' 突然変異(挿入.ある長さの遺伝子を挿入する) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_ins(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim l As Integer Dim ld As Integer Dim p As Integer ' ' データのチェック ' If dup_a = 0 or min_len < 0 Console.WriteLine("***error 突然変異方法が不適当 (M_ins)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' 挿入位置の決定 p = Math.Floor(rn.NextDouble() * (len(i1)+1)) If p > len(i1) p = len(i1) End If ' 挿入する遺伝子長の決定 If wd = 0 l = Math.Floor(rn.NextDouble() * (max_len - len(i1) + 1)) else l = wd End If If l > max_len-len(i1) l = max_len - len(i1) Else If l <= 0 l = 1 End If End If ' 実行 ' 挿入場所の確保 If p < len(i1) For i2 = len(i1)+l-1 To p Step -1 ind(i1,i2) = ind(i1,i2-l) Next End If ' 挿入場所の遺伝子の決定 For i2 = p To p ld = Math.Floor(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l) If ld > allele_u ld = allele_u End If ind(i1,i2) = ld Next len(i1) += l End If Next End Sub '********************************************************************' ' 突然変異(削除.ある長さの遺伝子を削除する) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_del(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim l As Integer Dim max As Integer Dim p As Integer ' ' データのチェック ' If dup_a = 0 or min_len < 0 Console.WriteLine("***error 突然変異方法が不適当 (M_del)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' 削除位置の決定 p = Math.Floor(rn.NextDouble() * len(i1)) If p >= len(i1) p = len(i1) - 1 End If ' 削除する遺伝子長の決定 If len(i1)-min_len < len(i1)-p max = len(i1) - min_len Else max = len(i1) - p End If If wd = 0 l = Math.Floor(rn.NextDouble() * max + 1) Else l = wd End If If l > max l = max End If ' 実行 For i2 = 0 To len(i1)-p-l-1 ind(i1,p+i2) = ind(i1,p+i2+l) Next len(i1) -= l End If Next End Sub '*******************************************************************' ' 淘汰(エリート・ルーレット選択) ' ' elite : エリートで残す個体数(default=0) ' ' s_method : ルーレット板の作成方法(default=1) ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' s_bias : α,または,method=2の場合は初期値(default=0) ' ' s_step : β(default=1) ' '*******************************************************************' Sub S_roul(elite As Integer, s_method As Integer, s_bias As Double, s_step As Double) Dim count As Integer = 0 Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k As Integer = 0 Dim max As Integer Dim n As Integer = 0 Dim p As Integer Dim sw As Integer ' ' 値のチェックと初期設定 ' If s_method <> 0 and s_method <> 2 s_method = 1 End If If elite > size Console.WriteLine("***error エリートで残す数が多すぎる (S_roul)") Environment.Exit(1) End If If s_method = 2 and s_step <= 0.0 s_step = 1.0 End If For i1 = 0 To size+max_ch-1 s_w(i1) = 0 Next ' ' 重複個体を削除 ' If dup_s = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 0 For i2 = i1+1 To size+max_ch-1 If pi_w(i2) > 0 and len(i1) = len(i2) sw = 0 i3 = 0 Do While i3 < len(i1) and sw = 0 If ind(i1,i3) <> ind(i2,i3) sw = 1 End If i3 += 1 Loop If sw = 0 pi_w(i2) = 0 End If End If Next End If Next End If For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 n += 1 End If Next If n < 0 or dup_s = 0 and n < size Console.WriteLine("***error 残す個体がない (S_roul)") Environment.Exit(1) End If ' ' 淘汰して残す個体を選ぶ ' ' エリートの選択 sw = 0 Do While k < elite and k < n and sw = 0 max = -1 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 and s_w(i1) = 0 If max < 0 max = i1 ElseIf pi(i1) > pi(max) max = i1 End If End If Next If max < 0 sw = 1 Else s_w(max) = 1 k += 1 End If Loop ' ルーレット選択 Do While count < size+max_ch and k < size p = Select_f(s_method, s_bias, s_step) If dup_s = 0 and s_w(p) > 0 count += 1 Else count = 0 s_w(p) += 1 k += 1 End If Loop ' 選択に失敗した場合の処理 If dup_s = 0 and k < size i1 = 0 Do While i1 < size+max_ch and k < size If pi_w(i1) > 1 and s_w(i1) = 0 s_w(i1) = 1 k += 1 End If i1 += 1 Loop End If ' 複数回選択されたものの処理 For i1 = 0 To size+max_ch-1 If s_w(i1) = 0 pi_w(i1) = 0 End If Next For i1 = 0 To size+max_ch-1 If s_w(i1) > 0 If s_w(i1) > 1 For i2 = 2 To s_w(i1) k = Position(-1) len(k) = len(i1) pi_w(k) = 2 pi(k) = pi(i1) For i3 = 0 To len(i1)-1 ind(k,i3) = ind(i1,i3) Next Next End If End If Next End Sub End Class '*****************' ' クラスTSPの定義 ' '*****************' Class TSP Inherits Species ' クラス Species を継承 Private max_gen As Integer ' 最大世代交代数 Private kosa_m As Integer ' 交叉方法 ' =-1 : 交叉を使用しない ' =0 : 親のコピー ' =1 : 循環交叉 ' =2 : 部分的交叉 ' =3 : 順序交叉 ' =4 : 一様順序交叉 ' =5 : 一様位置交叉 ' =6 : エッジ組み替え交叉 ' =7 : サブツアー交叉 Private kosa As Double ' 交叉確率 Private k_point As Integer ' 交差点の数(負の時は,1から-point間のランダム) Private k_vr As Integer ' =0 : 両親とも同じ位置で交叉 ' =1 : 両親が異なる位置で交叉(遺伝子長は可変) Private k_method As Integer ' 交叉の時の親の選択方法 ' =-1 : ランダム ' =0 : 適応度をそのまま使用 ' =1 : 最小値からの差(ただし,α以下の場合はα) ' =2 : 評価値に順位をつけ,減少率βで線形化 Private k_bias As Double ' α,または,method=2の場合は初期値 Private k_step As Double ' β Private mute_m As Integer ' 突然変異方法 ' =-1 : 突然変異を使用しない ' =0 : 移動 ' =1 : 逆位 ' =2 : スクランブル ' =3 : 転座 Private mute As Double ' 突然変異率 Private wd As Integer ' 突然変異に使用する部分遺伝子長 Private m_mean As Double ' 摂動の平均値 Private m_std As Double ' 摂動の標準偏差 Private elite As Integer ' エリート選択で残す数 Private s_method As Integer ' ルーレット板の作成方法 ' =0 : 適応度をそのまま使用 ' =1 : 最小値からの差(ただし,α以下の場合はα) ' =2 : 評価値に順位をつけ,減少率βで線形化 Private s_bias As Double ' α,または,s_method=2の場合は初期値 Private s_step As Double ' β Private out_d As Integer ' 表示間隔 Private out_lvl As Integer ' 出力レベル ' =0 : 最終出力だけ ' n>0 : n世代毎に出力(負の時はファイル) Private out_m As Integer ' 出力方法 ' =0 : すべてを出力 ' =1 : 最大適応度の個体だけを出力 Private o_file As String ' 出力ファイル名 Private n_city As Integer ' 都市の数 Private rg(,) As Integer ' 都市間の距離 Private kinbo As Integer ' 近傍探索(0:行わない,1:行う) Private neib As Integer ' 近傍(2 or 3) Private sel As Integer ' エッジの選択方法 ' =0 : 最良のものを選択 ' =1 : 最初のものを選択 Private city(,) As Integer '都市の位置データ '*************************************' ' コンストラクタ ' ' name1 : Species定義ファイル名 ' ' name2 : TSP定義ファイル名 ' ' seed : 乱数の初期値 ' '*************************************' Public Sub New (name1 As String, name2 As String, seed As Integer) MyBase.new(name1, seed) ' 基底クラスのコンストラクタ Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name2) ' 基本データの入力 ' 1行目 Dim str() As String = MS.Split(inp.ReadLine().Trim()) out_lvl = Integer.Parse(str(1)) out_m = Integer.Parse(str(3)) ' 2行目 str = MS.Split(inp.ReadLine().Trim()) o_file = str(1) out_d = Integer.Parse(str(3)) ' 3行目 str = MS.Split(inp.ReadLine().Trim()) kosa_m = Integer.Parse(str(1)) kosa = Double.Parse(str(3)) k_point = Integer.Parse(str(5)) k_vr = Integer.Parse(str(7)) k_method = Integer.Parse(str(9)) k_bias = Double.Parse(str(11)) k_step = Double.Parse(str(13)) ' 4行目 str = MS.Split(inp.ReadLine().Trim()) mute_m = Integer.Parse(str(1)) mute = Double.Parse(str(3)) wd = Integer.Parse(str(5)) m_mean = Double.Parse(str(7)) m_std = Double.Parse(str(9)) ' 5行目 str = MS.Split(inp.ReadLine().Trim()) elite = Integer.Parse(str(1)) s_method = Integer.Parse(str(3)) s_bias = Double.Parse(str(5)) s_step = Double.Parse(str(7)) ' 6行目 str = MS.Split(inp.ReadLine().Trim()) n_city = Integer.Parse(str(1)) max_gen = Integer.Parse(str(3)) ' 7行目 str = MS.Split(inp.ReadLine().Trim()) kinbo = Integer.Parse(str(1)) neib = Integer.Parse(str(3)) ' 8行目 str = MS.Split(inp.ReadLine().Trim()) sel = Integer.Parse(str(1)) If kinbo > 0 and neib <> 2 and neib <> 3 Console.WriteLine("***error 近傍の値が不適当") Environment.Exit(1) End If If n_city <> max_len Console.WriteLine("***error 都市数が不適当") Environment.Exit(1) End If ' 都市の位置データ ReDim city(n_city, 2) For i1 As Integer = 0 To n_city-1 str = MS.Split(inp.ReadLine().Trim()) city(i1,0) = Integer.Parse(str(0)) city(i1,1) = Integer.Parse(str(1)) Next inp.Close() ' 距離テーブル ReDim rg(n_city, n_city) For i1 As Integer = 0 To n_city-1 For i2 As Integer = i1+1 To n_city-1 Dim x As Double = city(i2,0) - city(i1,0) Dim y As Double = city(i2,1) - city(i1,1) rg(i1,i2) = Math.Floor(Math.Sqrt(x * x + y * y) + 0.5) Next Next For i1 As Integer = 1 To n_city-1 For i2 As Integer = 0 To i1-1 rg(i1,i2) = rg(i2,i1) Next Next End Sub '************' ' 全体の制御 ' '************' Sub Control() Dim gen As Integer = 1 ' 初期集団の発生 Init_std() ' 評価 If kinbo > 0 Kinbo_s() Else Adap() End If ' 画面表示 Console.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean) ' 出力 If Math.Abs(out_lvl) > 0 Output(gen) End If ' 世代交代 For gen = 2 To max_gen ' 交叉 Select Case kosa_m Case 0 C_copy(2, max_ch/2, k_method, k_bias, k_step) ' 親のコピー Case 1 C_cycle(kosa, k_method, k_bias, k_step) ' 循環交叉 Case 2 C_part(kosa, k_method, k_bias, k_step) ' 部分的交叉 Case 3 C_seq(kosa, k_method, k_bias, k_step) ' 順序交叉 Case 4 C_useq(kosa, k_method, k_bias, k_step) ' 一様順序交叉 Case 5 C_upos(kosa, k_method, k_bias, k_step) ' 一様位置交叉 Case 6 C_edge(kosa, k_method, k_bias, k_step) ' エッジ組み替え交叉 Case 7 C_sub(kosa, k_point) ' サブツアー交叉 End Select ' 突然変異 Select Case mute_m Case 0 M_move(mute) ' 移動 Case 1 M_inv(mute, wd) ' 逆位 Case 2 M_scram(mute, wd) ' スクランブル Case 3 M_chg(mute, wd) ' 転座 End Select ' 適応度 If kinbo > 0 Kinbo_s() Else Adap() End If ' 淘汰 S_roul(elite, s_method, s_bias, s_step) ' 表示 If (gen Mod out_d) = 0 Console.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean) End If If Math.Abs(out_lvl) > 0 If (gen Mod Math.Abs(out_lvl)) = 0 Output(gen) End If End If Next gen -= 1 Dim k1 As Integer = out_m out_m = 0 Console.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean) Output(gen) out_m = k1 End Sub '***************************' ' 結果の出力 ' ' gen : 現在の世代番号 ' '***************************' Sub Output(gen As Integer) Dim pr As Integer = -1 If out_lvl >= 0 Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer.Parse(Console.ReadLine()) End If If pr <> 0 Dim Out As StreamWriter = new StreamWriter(o_file, true) ' 出力先の決定と評価値の出力 If pr < 0 Dim now1 As DateTime = DateTime.Now ' 現在時刻の獲得 OUT.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean & " 時間 " & now1) End If ' 巡回順序の出力 If out_m = 0 Dim k As Integer = 0 For i1 As Integer = 0 To len(max_n)-1 Dim n As Integer = ind(max_n,i1) If pr < 0 OUT.WriteLine(n & " " & city(n,0) & " " & city(n,1)) Else Console.WriteLine(n & " " & city(n,0) & " " & city(n,1)) End If If pr > 0 k += 1 If k = pr Console.ReadLine() k = 0 End If End If Next End If OUT.Close() End If End Sub '*******************************' ' 距離の計算 ' ' n_c : 都市の数 ' ' p : 都市番号 ' ' return : 距離(負) ' '*******************************' Function Kyori(n_c As Integer, p() As Integer) Dim range As Integer = 0 Dim n1 As Integer = p(0) Dim n2 As Integer For i1 As Integer = 1 To n_c-1 n2 = p(i1) range -= rg(n1,n2) n1 = n2 Next n2 = p(0) range -= rg(n1,n2) Return range End Function '**************' ' 適応度の計算 ' '**************' Sub Adap() Dim i1 As Integer Dim i2 As Integer Dim k As Integer = 0 mean = 0.0 max = 0.0 max_n = -1 For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 pi_w(i1) = 2 Dim ind1(len(i1)) As Integer For i2 = 0 To len(i1)-1 ind1(i2) = ind(i1,i2) Next pi(i1) = Kyori(len(i1), ind1) End If If pi_w(i1) > 0 k += 1 mean += pi(i1) If max_n < 0 or pi(i1) > max max = pi(i1) max_n = i1 End If End If Next If k > 0 mean /= k End If End Sub '************' ' 近傍の探索 ' '************' Sub Kinbo_s() Dim i1 As Integer Dim i2 As Integer Dim k As Integer = 0 Dim sw As Integer Dim r As Integer max = 0.0 max_n = -1 mean = 0.0 For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 pi_w(i1) = 2 sw = 1 Dim ind1(len(i1)) As Integer For i2 = 0 To len(i1)-1 ind1(i2) = ind(i1,i2) Next r = Kyori(len(i1), ind1) Do While sw > 0 sw = Change(len(i1), ind1, r) If sw > 0 For i2 = 0 To len(i1)-1 ind(i1,i2) = ind1(i2) Next End If Loop pi(i1) = r End If If pi_w(i1) > 0 k += 1 mean += pi(i1) If max_n < 0 or pi(i1) > max max = pi(i1) max_n = i1 End If End If Next If k > 0 mean /= k End If End Sub '************************************' ' エッジの入れ替え ' ' n_city : 都市の数 ' ' seq : 訪問する順番 ' ' r_m : 距離の負値 ' ' return : =0 : 改善がなかった ' ' =1 : 改善があった ' '************************************' Function Change(n_city As Integer, seq() As Integer, ByRef r_m As Integer) Dim ch As Integer = 0 Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim k As Integer Dim k1 As Integer Dim k2 As Integer Dim max As Integer Dim n1 As Integer Dim n2 As Integer Dim n3 As Integer Dim nn As Integer Dim r As Integer Dim sw As Integer = 0 max = r_m n3 = Math.Floor(rn.NextDouble() * (n_city - 2)) If n3 > n_city-3 n3 = n_city - 3 End If ' 2近傍 i1 = 0 Do While i1 <= n_city-3 and ch = 0 If n3 = 0 n1 = n_city - 2 Else n1 = n_city - 1 End If i2 = n3 + 2 Do While i2 <= n1 and ch = 0 ' 枝の場所((n3,n3+1), (k1,k2)) k1 = i2 If i2 = n_city-1 k2 = 0 Else k2 = i2 + 1 End If ' 枝の入れ替え kou1(0) = seq(n3) k = 1 For i3 = k1 To n3+1 Step -1 kou1(k) = seq(i3) k += 1 Next nn = k2 Do While nn <> n3 kou1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価 r = Kyori(n_city, kou1) If r > max max = r sw = 1 For i3 = 0 To n_city-1 kou2(i3) = kou1(i3) Next If sel > 0 ch = 1 End If End If i2 += 1 Loop n3 += 1 If n3 > n_city-3 n3 = 0 End If i1 += 1 Loop ' 3近傍 If neib = 3 and ch = 0 i1 = 0 Do While i1 <= n_city-3 and ch = 0 n1 = n_city - 2 n2 = n_city - 1 i2 = n3 + 1 Do While i2 <= n1 and ch = 0 i3 = i2 + 1 Do While i3 <= n2 and ch = 0 ' 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2)) k1 = i3 If i3 = n_city-1 k2 = 0 Else k2 = i3 + 1 End If ' 枝の入れ替えと評価 ' 入れ替え(その1) kou1(0) = seq(n3) k = 1 For i4 = i2 To n3+1 Step -1 kou1(k) = seq(i4) k += 1 Next For i4 = k1 To i2+1 Step -1 kou1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 kou1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その1) r = Kyori(n_city, kou1) If r > max max = r sw = 1 For i3 = 0 To n_city-1 kou2(i3) = kou1(i3) Next If sel > 0 ch = 1 End If End If ' 入れ替え(その2) kou1(0) = seq(n3) k = 1 For i4 = k1 To i2+1 Step -1 kou1(k) = seq(i4) k += 1 Next For i4 = n3+1 To i2 kou1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 kou1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その2) r = Kyori(n_city, kou1) If r > max max = r sw = 1 For i3 = 0 To n_city-1 kou2(i3) = kou1(i3) Next If sel > 0 ch = 1 End If End If ' 入れ替え(その3) kou1(0) = seq(n3) k = 1 For i4 = i2+1 To k1 kou1(k) = seq(i4) k += 1 Next For i4 = i2 To n3+1 Step -1 kou1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 kou1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その3) r = Kyori(n_city, kou1) If r > max max = r sw = 1 For i3 = 0 To n_city-1 kou2(i3) = kou1(i3) Next If sel > 0 ch = 1 End If End If ' 入れ替え(その4) kou1(0) = seq(n3) k = 1 For i4 = i2+1 To k1 kou1(k) = seq(i4) k += 1 Next For i4 = n3+1 To i2 kou1(k) = seq(i4) k += 1 Next nn = k2 Do While nn <> n3 kou1(k) = seq(nn) k += 1 nn += 1 If nn > n_city-1 nn = 0 End If Loop ' 評価(その4) r = Kyori(n_city, kou1) If r > max max = r sw = 1 For i3 = 0 To n_city-1 kou2(i3) = kou1(i3) Next If sel > 0 ch = 1 End If End If i3 += 1 Loop i2 += 1 Loop n3 += 1 If n3 > n_city-3 n3 = 0 End If i1 += 1 Loop End If ' 設定 If sw > 0 r_m = max For i1 = 0 To n_city-1 seq(i1) = kou2(i1) Next End If return sw End Function End Class End Module //----------------ケーススタディデータ(data_ct.txt)------ /* 3 data1_t.txt data2_t.txt data1_t.txt data2_t.txt data1_t.txt data2_t.txt */ //---------------Species記述データ(data1_t.txt)--------- /* 対立遺伝子上限 9 対立遺伝子下限 0 最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 0 個体の重複(同じ染色体の個体) 0 集団サイズ 10 子供 10 */ //---------------TSP記述データ(data2_t.txt)-------- /* 出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0 出力ファイル名 out1.txt 表示間隔 10 交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 都市数 10 最大世代交代数 2000 近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2 選択方法(0:最良,1:最初) 1 -58 37 55 -19 6 -79 27 -30 44 -94 33 -58 -94 87 -9 3 33 69 43 -57 */
'******************************************************************' ' f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値 ' ' coded by Y.Suganuma ' '******************************************************************' Imports System.IO Imports System.Text.RegularExpressions Module Test Sub Main(args() As String) ' 入力ミス If args.Length = 0 Console.WriteLine("***error ケーススタディファイル名を入力して下さい") ' 入力OK Else ' 入力データファイル名の入力 Dim inp As StreamReader = New StreamReader(args(0)) Dim MS As Regex = New Regex("\s+") Dim n As Integer = Integer.Parse(inp.ReadLine().Trim()) ' 問題の数 Dim i_file1(n) As String Dim i_file2(n) As String For i1 As Integer = 0 To n-1 Dim str() As String = MS.Split(inp.ReadLine().Trim()) i_file1(i1) = str(0) i_file2(i1) = str(1) Next inp.Close() ' 実行(乱数の初期値を変える) For i1 As Integer = 0 To n-1 Console.WriteLine() Console.WriteLine("+++++ケース " & (i1+1) & "+++++") ' 入力と初期設定 Dim kn As Kansu = new Kansu (i_file1(i1), i_file2(i1), 1000 * i1 + 1234567) ' 最適化 kn.Control() Next End If End Sub '*********************' ' クラスSpeciesの定義 ' '*********************' Class Species protected max As Double ' 最大適応度 protected mean As Double ' 平均適応度 protected pi() As Double ' 適応度 protected ro() As Double ' ルーレット板 protected allele_u As Integer ' 対立遺伝子上限 protected allele_l As Integer ' 対立遺伝子下限 protected size As Integer ' 個体総数 protected max_ch As Integer ' 子供の数の最大値 protected max_len As Integer ' 最大遺伝子長 protected min_len As Integer ' 最小遺伝子長(負の時は,最大遺伝子長で固定) protected max_n As Integer ' 最大適応度の個体番号 protected dup_a As Integer ' 遺伝子の重複 ' =0 : 重複を許さない ' =1 : 重複を許す protected dup_s As Integer ' 個体の重複(同じ染色体の個体) ' =0 : 重複を許さない ' =1 : 重複を許す protected ind(,) As Integer ' 集団(個体の集まり) protected len() As Integer ' 各個体の遺伝子長 protected kou1() As Integer ' 交叉・突然変異用作業場所1 protected kou2() As Integer ' 交叉・突然変異用作業場所2 protected s_w() As Integer ' 淘汰用指標(選択された回数) protected edge(,) As Integer ' エッジ組み替え交叉用ワークエリア protected pi_w() As Integer ' 適応度計算指標 ' =0 : 未使用 ' =1 : 適応度計算前(突然変異はこの個体だけに適用) ' =2 : 適応度計算済み(交叉時に親とみなす) protected rn As Random ' 乱数 '**************************' ' コンストラクタ ' ' name : ファイル名 ' ' seed : 乱数の初期値 ' '**************************' Public Sub New (name As String, seed As Integer) Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name) ' ' データの入力 ' ' 1行目 Dim str() As String = MS.Split(inp.ReadLine().Trim()) allele_u = Integer.Parse(str(1)) allele_l = Integer.Parse(str(3)) ' 2行目 str = MS.Split(inp.ReadLine().Trim()) max_len = Integer.Parse(str(1)) min_len = Integer.Parse(str(3)) ' 3行目 str = MS.Split(inp.ReadLine().Trim()) dup_a = Integer.Parse(str(1)) dup_s = Integer.Parse(str(3)) ' 4行目 str = MS.Split(inp.ReadLine().Trim()) size = Integer.Parse(str(1)) max_ch = Integer.Parse(str(3)) inp.Close() ' ' データのチェック ' If size <= 0 Console.WriteLine("***error 個体総数≦0 (Constructor)") Environment.Exit(1) End If If max_ch < 0 Console.WriteLine("***error 子供の数<0 (Constructor)") Environment.Exit(1) End If If max_len <= 0 or min_len = 0 Console.WriteLine("***error 遺伝子長≦0 (Constructor)") Environment.Exit(1) End If If max_len < min_len Console.WriteLine("***error 最大遺伝子長<最小遺伝子長 (Constructor)") Environment.Exit(1) End If If allele_u <= allele_l Console.WriteLine("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)") Environment.Exit(1) End If Dim kind As Integer = allele_u - allele_l + 1 If dup_a = 0 and max_len > kind Console.WriteLine("***error 遺伝子の重複を防ぐことはできない (Constructor)") Environment.Exit(1) End If ' ' 領域の確保 ' Dim num As Integer = size + max_ch ReDim ind(num, max_len) ReDim edge(max_len, 5) ReDim pi(num) ReDim ro(num) ReDim len(num) ReDim kou1(max_len) ReDim kou2(max_len) ReDim s_w(num) ReDim pi_w(num) ' ' 乱数の初期設定 ' rn = new Random(seed) End Sub '*********************************' ' 正規分布変量の発生 ' ' m : 平均 ' ' s : 標準偏差 ' ' return : 正規分布変量 ' '*********************************' Function norm_d(m As Double, s As Double) Dim x As Double = 0.0 For i1 As Integer = 0 To 11 x += rn.NextDouble() Next x = s * (x - 6.0) + m Return x End Function '************************************************' ' 場所を探す ' ' n : >=0 : n番目の親を捜す ' ' -1 : 空いている場所を探す ' ' return : 親の場所,または,空いている場所 ' ' (存在しないときは負の値) ' '************************************************' Function Position(n As Integer) Dim i1 As Integer Dim k As Integer = -1 Dim sw As Integer = 0 ' ' 空いている場所を探す ' If n < 0 i1 = 0 Do While i1 < size+max_ch and k < 0 If pi_w(i1) = 0 k = i1 End If i1 += 1 Loop If k < 0 Console.WriteLine("***error 空いている場所がない --Position--") Environment.Exit(1) End If ' ' n番目の親(pi_w(i)=2)を捜す ' Else i1 = 0 Do While i1 < size+max_ch and sw = 0 If pi_w(i1) = 2 k += 1 If k = n sw = 1 k = i1 End If End If i1 += 1 Loop End If Return k End Function '*****************************************************************' ' 個体の選択 ' ' method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' bias : α,または,method=2の場合は初期値 ' ' sttp : β ' ' return : 個体番号 ' '*****************************************************************' Function Select_f(method As Integer, bias As Double, sttp As Double) Dim sum As Double = 0.0 Dim x As Double Dim i1 As Integer Dim k As Integer Dim min As Integer Dim n As Integer Dim sw As Integer ' ルーレット板の用意 Select Case method ' ランダム Case -1 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 n += 1 End If Next sum = 1.0 / n For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = sum End If Next ' 評価値をそのまま利用 Case 0 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 sum += pi(i1) n += 1 End If Next If Math.Abs(sum) > 1.0e-10 sum = 1.0 / Math.Abs(sum) For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = pi(i1) * sum End If Next Else sum = 1.0 / n For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = sum End If Next End If ' 最小値からの差 Case 1 min = -1 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 n += 1 If min < 0 min = i1 ElseIf pi(i1) < pi(min) min = i1 End If End If Next For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = pi(i1) - pi(min) If ro(i1) < bias ro(i1) = bias End If sum += ro(i1) End If Next If sum > 1.0e-10 sum = 1.0 / sum For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) *= sum End If Next Else sum = 1.0 / n For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = sum End If Next End If ' 線形化 Case 2 n = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) = -1.0 n += 1 Else ro(i1) = 1.0 End If Next sw = 0 sum = bias Do while sw = 0 min = -1 For i1 = 0 To size+max_ch-1 If ro(i1) < 0.0 If min < 0 min = i1 ElseIf pi(i1) < pi(min) min = i1 End If End If Next If min < 0 sw = 1 Else ro(min) = sum sum += sttp End If Loop sum = 1.0 / (0.5 * (2.0 * bias + sttp * (n - 1)) * n) For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 ro(i1) *= sum End If Next End Select sum = 0.0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 sum += ro(i1) ro(i1) = sum End If Next ' 選択 x = rn.NextDouble() sw = 0 k = 0 i1 = 0 Do While i1 < size+max_ch and sw = 0 If pi_w(i1) > 1 If x <= ro(i1) sw = 1 k = i1 End If End If i1 += 1 Loop Return k End Function '******************' ' 標準的な初期設定 ' '******************' Sub Init_std() Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim length As Integer Dim lid As Integer Dim sw1 As Integer Dim sw2 As Integer ' ' 初期設定 ' For i1 = 0 To size+max_ch-1 If i1 < size pi_w(i1) = 1 ' 適応度の計算前 Else pi_w(i1) = 0 ' 未使用 End If Next ' ' 遺伝子の決定 ' For i1 = 0 To size-1 sw1 = 0 Do While sw1 = 0 ' 遺伝子長の決定 If min_len < 0 length = max_len Else length = Math.Floor(rn.NextDouble() * (max_len - min_len + 1) + min_len) If length > max_len length = max_len End If End If len(i1) = length ' 遺伝子の決定 For i2 = 0 To length-1 sw2 = 0 Do While sw2 = 0 lid = Math.Floor(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l) If lid > allele_u lid = allele_u End If ind(i1,i2) = lid ' 重複遺伝子のチェック sw2 = 1 If dup_a = 0 i3 = 0 Do While i3 < i2 and sw2 > 0 If lid = ind(i1,i3) sw2 = 0 End If i3 += 1 Loop End If Loop Next ' 重複個体のチェック sw1 = 1 If dup_s = 0 i2 = 0 Do While i2 < i1 and sw1 > 0 If len(i1) = len(i2) sw2 = 0 i3 = 0 Do While i3 < len(i1) and sw2 = 0 If ind(i1,i3) <> ind(i2,i3) sw2 = 1 End If i3 += 1 Loop If sw2 = 0 sw1 = 0 End If End If i2 += 1 Loop End If Loop Next End Sub '**************************************************' ' 標準的な出力 ' ' sw : 出力レベル ' ' =0 : 最終出力だけ ' ' n>0 : n世代毎に出力(負はファイル) ' ' out_m : 出力方法 ' ' =0 : すべての個体を出力 ' ' =1 : 最大適応度の個体だけを出力 ' ' gen : 現在の世代番号 ' ' name : 出力ファイル名 ' '**************************************************' Sub Out_std(sw As Integer, out_m As Integer, gen As Integer, name As String) Dim pr As Integer = -1 If sw >= 0 Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer.Parse(Console.ReadLine()) End If If pr <> 0 Dim OUT As StreamWriter = new StreamWriter(name, true) ' 出力先の決定と評価値の出力 If pr < 0 Dim now1 As DateTime = DateTime.Now ' 現在時刻の獲得 OUT.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean & " 時間 " & now1) End If ' 詳細出力 Dim k As Integer = 0 For i1 As Integer = 0 To size+max_ch-1 If (pi_w(i1) > 1) and (out_m = 0 or out_m = 1 and i1 = max_n) If pr < 0 OUT.Write(i1 & " allele") For i2 As Integer = 0 To len(i1)-1 OUT.Write(" " & ind(i1,i2)) Next OUT.WriteLine(" value " & pi(i1)) Else Console.Write(i1 & " allele") For i2 As Integer = 0 To len(i1)-1 Console.Write(" " & ind(i1,i2)) Next Console.WriteLine(" value " & pi(i1)) End If If pr > 0 k += 1 If k = pr Console.ReadLine() k = 0 End If End If End If Next OUT.Close() End If End Sub '*****************************************************************' ' 交叉(親のコピー) ' ' method : =2 : 有性(2つの親から2つの子供) ' ' =1 : 1つの親から1つの子供 ' ' pair : method=2 の時は親のペア数 ' ' method=1 の時は親の数(=子供の数) ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_copy(method As Integer, pair As Integer, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータチェック ' If method <> 1 method = 2 End If If pair <= 0 If method = 2 pair = max_ch / 2 Else pair = max_ch End If Else If method = 2 and 2*pair > max_ch or method = 1 and pair > max_ch Console.WriteLine("***error 子供が多すぎる (C_copy)") Environment.Exit(1) End If End If ' ' 実行 ' For i1 = 0 To pair-1 ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do while sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' コピー For i2 = 0 To method-1 If i2 = 0 p = p1 Else p = p2 End If k = Position(-1) len(k) = len(p) pi_w(k) = 1 For i3 = 0 To len(k)-1 ind(k,i3) = ind(p,i3) Next Next Next End Sub '*****************************************************************' ' 交叉(多点交叉) ' ' kosa : 交叉確率 ' ' k_point : 交叉点の数 ' ' (負の時は,1から-k_point間のランダム) ' ' k_vr : =0 : 両親とも同じ位置で交叉 ' ' =1 : 両親が異なる位置で交叉(遺伝子長は可変) ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_point(kosa As Double, k_point As Integer, k_vr As Integer, k_method As Integer, k_bias As Double, k_step As Double) Dim abs_p As Integer Dim c1 As Integer Dim c2 As Integer Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim mn As Integer = 0 Dim num As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim pair As Integer Dim sw As Integer Dim t11 As Integer Dim t12 As Integer Dim t21 As Integer Dim t22 As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a = 0 Console.WriteLine("***error 交叉方法が不適当 (C_point)") Environment.Exit(1) End If abs_p = Math.Abs(k_point) If abs_p = 0 or abs_p > max_len-1 or min_len > 0 and abs_p > min_len-1 Console.WriteLine("***error 交叉点の数が不適当 (C_point)") Environment.Exit(1) End If If k_vr > 0 and min_len < 0 Console.WriteLine("***error 遺伝子長は可変でなければならない (C_point)") Environment.Exit(1) End If ' ' 交叉 ' num = k_point For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 交叉位置の数の決定 If k_point < 0 num = Math.Floor(rn.NextDouble() * abs_p + 1) If num > abs_p num = abs_p End If End If ' 交叉位置の決定(点の後ろで交叉) For i2 = 0 To num-1 ' 親1の交叉位置 sw = 0 Do While sw = 0 sw = 1 kou1(i2) = Math.Floor(rn.NextDouble() * (len(p1) - 1)) If kou1(i2) > len(p1)-2 kou1(i2) = len(p1) - 2 End If If k_vr = 0 and kou1(i2) > len(p2)-2 kou1(i2) = len(p2) - 2 End If i3 = 0 Do While i3 < i2 and sw > 0 If kou1(i3) = kou1(i2) sw = 0 End If i3 += 1 Loop Loop ' 親2の交叉位置 If k_vr > 0 sw = 0 Do While sw = 0 sw = 1 kou2(i2) = Math.Floor(rn.NextDouble() * (len(p2) - 1)) If kou2(i2) > len(p2)-2 kou2(i2) = len(p2) - 2 End If i3 = 0 Do While i3 < i2 and sw > 0 If kou2(i3) = kou2(i2) sw = 0 End If i3 += 1 Loop Loop End If Next ' 交叉の実行 ' 親1のt11からt12を子1のc1へコピー ' 親2のt21からt22を子2のc2へコピー ' 次は, ' 親1のt11からt12を子2のc2へコピー ' 親2のt21からt22を子1のc1へコピー ' ・・・・・ c1 = 0 c2 = 0 t11 = 0 t21 = 0 ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) For i2 = 0 To num ' 次の交叉位置を求める If i2 = num ' 最後 t12 = len(p1) t22 = len(p2) Else ' 親1 t12 = max_len For i3 = 0 To num-1 If kou1(i3) >= 0 and kou1(i3) <= t12 t12 = kou1(i3) mn = i3 End If Next kou1(mn) = -1 t12 += 1 ' 親2 If k_vr = 0 t22 = t12 Else t22 = max_len For i3 = 0 To num-1 If kou2(i3) >= 0 and kou2(i3) <= t22 t22 = kou2(i3) mn = i3 End If Next kou2(mn) = -1 t22 += 1 End If End If ' 指定箇所のコピー For i3 = t11 To t12-1 If (i2 Mod 2) = 0 If c1 < max_len ind(k1,c1) = ind(p1,i3) c1 += 1 End If Else If c2 < max_len ind(k2,c2) = ind(p1,i3) c2 += 1 End If End If Next For i3 = t21 To t22-1 If (i2 Mod 2) = 0 If c2 < max_len ind(k2,c2) = ind(p2,i3) c2 += 1 End If Else If c1 < max_len ind(k1,c1) = ind(p2,i3) c1 += 1 End If End If Next ' 交叉位置の移動 t11 = t12 t21 = t22 Next End If Next End Sub '*****************************************************************' ' 交叉(一様交叉.(0,1)を等確率で発生させ,1であれば, ' ' 親1,0であれば親2の遺伝子を子1が受け継ぐ) ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_uniform(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim k1 As Integer Dim k2 As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim pair As Integer Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a = 0 Console.WriteLine("***error 交叉方法が不適当 (C_unIForm)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_unIForm)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 For i2 = 0 To len(p1)-1 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) End If Next End If Next End Sub '*****************************************************************' ' 交叉(平均化交叉.2つの親の平均値を受け継ぐ) ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_mean(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim k As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_mean)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To max_ch-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(1, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k = Position(-1) len(k) = len(p1) pi_w(k) = 1 ' 交叉 For i2 = 0 To len(k)-1 ind(k,i2) = (ind(p1,i2) + ind(p2,i2)) / 2 Next End If Next End Sub '*****************************************************************' ' 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を ' ' そのまま各子供が選択する.その位置にある親2(1)の遺伝 ' ' 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継 ' ' ぐ(ただし,doubleの場合は,この手続きをのぞく).この手 ' ' 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り ' ' 返し,残りの遺伝子については,子1(2)は,親2(1)の ' ' 遺伝子をその順番通りに受け継ぐ) ' ' 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5 ' ' * → → ' ' 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_cycle(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_cycle)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_cycle)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 初期設定 For i2 = 0 To len(p1)-1 kou1(i2) = 0 kou2(i2) = 0 Next ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 sw = 0 Do While sw = 0 sw = 1 p = Math.Floor(rn.NextDouble() * len(p1)) If p >= len(p1) p = len(p1) - 1 End If If kou1(p) = 0 and kou2(p) = 0 kou1(p) = 1 kou2(p) = 1 ind(k1,p) = ind(p1,p) ind(k2,p) = ind(p2,p) i2 = 0 Do While i2 < len(p1) and sw > 0 If ind(p2,p) = ind(p1,i2) ind(k1,i2) = ind(p1,i2) kou1(i2) = 1 sw = 0 End If i2 += 1 Loop sw = 1 i2 = 0 Do While i2 < len(p2) and sw > 0 If ind(p1,p) = ind(p2,i2) ind(k2,i2) = ind(p2,i2) kou2(i2) = 1 sw = 0 End If i2 += 1 Loop End If Loop sw = 0 i2 = 0 i3 = 0 Do While sw = 0 Do While sw = 0 and i2 < len(p1) If kou1(i2) = 0 sw = 1 Else i2 += 1 End If Loop sw = 0 Do While sw = 0 and i3 < len(p2) If kou2(i3) = 0 sw = 1 Else i3 += 1 End If Loop If i2 < len(p1) and i3 < len(p2) ind(k1,i2) = ind(p2,i3) ind(k2,i3) = ind(p1,i2) sw = 0 i2 += 1 i3 += 1 Else sw = 1 End If Loop End If Next End Sub '*****************************************************************' ' 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と ' ' 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ ' ' の2つの遺伝子の位置を交換する.この操作を,選択した点よ ' ' り右にあるすべての遺伝子に対して実施する ' ' 2 4 1 3 6 5 2 4 5 3 6 1 ' ' * → → ・・・・・ ' ' 3 2 5 4 1 6 3 2 1 4 5 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_part(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim lv As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_part)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_part)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 p = Math.Floor(rn.NextDouble() * len(p1)) If p >= len(p1) p = len(p1) - 1 End If For i2 = 0 To len(p1)-1 ind(k1,i2) = ind(p1,i2) ind(k2,i2) = ind(p2,i2) Next For i2 = p To len(p1)-1 sw = 0 lv = ind(k1,i2) i3 = 0 Do While i3 < len(p1) and sw = 0 If ind(k2,i2) = ind(k1,i3) ind(k1,i2) = ind(k1,i3) ind(k1,i3) = lv sw = 1 End If i3 += 1 Loop sw = 0 i3 = 0 Do While i3 < len(p1) and sw = 0 If lv = ind(k2,i3) ind(k2,i3) = ind(k2,i2) ind(k2,i2) = lv sw = 1 End If i3 += 1 Loop Next End If Next End Sub '*****************************************************************' ' 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の ' ' 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1 ' ' の遺伝子を親2の遺伝子の出現順序に並べ替える. ' ' 2 4 1 3 6 5 2 4 1 3 5 6 ' ' * → ' ' 3 2 5 4 1 6 3 2 5 4 1 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_seq(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim pp As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_seq)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_seq)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 p = Math.Floor(rn.NextDouble() * (len(p1) - 1)) If p >= len(p1)-1 p = len(p1) - 2 End If For i2 = 0 To p ind(k1,i2) = ind(p1,i2) ind(k2,i2) = ind(p2,i2) Next pp = 0 For i2 = p+1 To len(p1)-1 sw = 0 i3 = pp Do While i3 < len(p2) and sw = 0 i4 = p + 1 Do While i4 < len(p1) and sw = 0 If ind(p2,i3) = ind(p1,i4) sw = 1 pp = i3 + 1 ind(k1,i2) = ind(p1,i4) End If i4 += 1 Loop i3 += 1 Loop Next pp = 0 For i2 = p+1 To len(p2)-1 sw = 0 i3 = pp Do While i3 < len(p1) and sw = 0 i4 = p + 1 Do While i4 < len(p2) and sw = 0 If ind(p1,i3) = ind(p2,i4) sw = 1 pp = i3 + 1 ind(k2,i2) = ind(p2,i4) End If i4 += 1 Loop i3 += 1 Loop Next End If Next End Sub '*****************************************************************' ' 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選 ' ' 択された位置における遺伝子の順序に従って,他の親の遺伝子 ' ' を並べ替える ' ' 2 4 1 3 6 5 2 4 1 3 6 5 ' ' * * → ' ' 3 2 5 4 1 6 4 2 5 3 1 6 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_useq(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_useq)\n") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_useq)\n") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 For i2 = 0 To len(p1)-1 ind(k1,i2) = ind(p1,i2) ind(k2,i2) = ind(p2,i2) If rn.NextDouble() < 0.5 kou1(i2) = 0 Else kou1(i2) = 1 End If Next p = 0 For i2 = 0 To len(p1)-1 If kou1(i2) > 0 sw = 0 i3 = p Do While i3 < len(p2) and sw = 0 i4 = 0 Do While i4 < len(p1) and sw = 0 If ind(p2,i3) = ind(p1,i4) and kou1(i4) > 0 sw = 1 p = i3 + 1 ind(k1,i2) = ind(p1,i4) End If i4 += 1 Loop i3 += 1 Loop End If Next p = 0 For i2 = 0 To len(p2)-1 If kou1(i2) > 0 sw = 0 i3 = p Do While i3 < len(p1) and sw = 0 i4 = 0 Do While i4 < len(p2) and sw = 0 If ind(p1,i3) = ind(p2,i4) and kou1(i4) > 0 sw = 1 p = i3 + 1 ind(k2,i2) = ind(p2,i4) End If i4 += 1 Loop i3 += 1 Loop End If Next End If Next End Sub '*****************************************************************' ' 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選 ' ' 択された位置における遺伝子の位置に,他の親の同じ遺伝子を ' ' 配置する.残りの遺伝子は,親と同じ順序に配置する. ' ' 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6 ' ' * * → → ' ' 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4 ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_upos(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k1 As Integer Dim k2 As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' pair = max_ch / 2 If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_upos)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_upos)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p2) ' 交叉 For i2 = 0 To len(p1)-1 If rn.NextDouble() < 0.5 kou1(i2) = 0 Else kou1(i2) = 1 End If If kou1(i2) > 0 ind(k1,i2) = ind(p2,i2) ind(k2,i2) = ind(p1,i2) End If Next p = 0 For i2 = 0 To len(p1)-1 sw = 0 i3 = 0 Do While i3 < len(p1) and sw = 0 If kou1(i3) > 0 and ind(p1,i2) = ind(k1,i3) sw = 1 End If i3 += 1 Loop If sw = 0 i3 = p Do While i3 < len(p1) and sw = 0 If kou1(i3) = 0 ind(k1,i3) = ind(p1,i2) p = i3 + 1 sw = 1 End If i3 += 1 Loop End If Next p = 0 For i2 = 0 To len(p2)-1 sw = 0 i3 = 0 Do While i3 < len(p2) and sw = 0 If kou1(i3) > 0 and ind(p2,i2) = ind(k2,i3) sw = 1 End If i3 += 1 Loop If sw = 0 i3 = p Do While i3 < len(p2) and sw = 0 If kou1(i3) = 0 ind(k2,i3) = ind(p2,i2) p = i3 + 1 sw = 1 End If i3 += 1 Loop End If Next End If Next End Sub '*****************************************************************' ' 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は ' ' 0~(max_len-1)である必要がある) ' ' (0) エッジマップを作成する.エッジマップとは,2つの親 ' ' を見て,ノードがどこに接続されているのかを表すもの ' ' であり,例えば,2つの親が, ' ' (A B C D E F) ' ' (B D C A E F) ' ' である場合は, ' ' A : B F C E ' ' B : A C D F ' ' C : B D A ' ' D : C E B ' ' E : D F A ' ' F : A E B ' ' となる. ' ' (1) 両親の2つの出発点の内1つで初期化する.ランダムま ' ' たはステップ(4)の基準に従って選ぶ(現在のノード) ' ' (2) エッジマップから,現在のノードを除く ' ' (3) 現在のノードが接続先のノードを持っていたら,(4)に ' ' 進む.さもなければ,(5)に進む ' ' (4) 現在のノードが持っている接続先ノードの内,最も少な ' ' い接続先ノードを持ったノードを選択し(同じ条件の場 ' ' 合は,ランダム),それを現在のノードとし,(2)に進む ' ' (5) 未接続のノードが残っていればランダムに選択し,(2)に ' ' 戻る.さもなければ,終了する ' ' kosa : 交叉確率 ' ' k_method : 選択方法 ' ' =-1 : ランダム ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' k_bias : α,または,method=2の場合は初期値 ' ' k_step : β ' '*****************************************************************' Sub C_edge(kosa As Double, k_method As Integer, k_bias As Double, k_step As Double) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim i5 As Integer Dim k As Integer Dim kk As Integer Dim k0 As Integer = 0 Dim k1 As Integer Dim k2 As Integer Dim min As Integer Dim num As Integer Dim p As Integer Dim pair As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer Dim e(2) As Integer ' ' 初期設定とデータのチェック ' pair = max_ch If dup_a <> 0 Console.WriteLine("***error 交叉方法が不適当 (C_edge)") Environment.Exit(1) End If If min_len > 0 Console.WriteLine("***error 遺伝子長は固定長でなければならない (C_edge)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To pair-1 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(1, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 親の選択 p1 = Select_f(k_method, k_bias, k_step) sw = 0 Do While sw = 0 p2 = Select_f(k_method, k_bias, k_step) If p1 <> p2 sw = 1 End If Loop ' 遺伝子長 k = Position(-1) pi_w(k) = 1 len(k) = len(p1) ' エッジマップの初期化 For i2 = 0 To len(k)-1 edge(i2,0) = 0 For i3 = 1 To 4 edge(i2,i3) = -1 Next Next ' 交叉 ' エッジマップの作成 For i2 = 0 To len(k)-1 sw = 0 i3 = 0 Do While i3 < len(k) and sw = 0 If i2 = ind(p1,i3) sw = 1 If i3 = 0 e(0) = ind(p1,len(k)-1) e(1) = ind(p1,1) Else If i3 = len(k)-1 e(0) = ind(p1,i3-1) e(1) = ind(p1,0) Else e(0) = ind(p1,i3-1) e(1) = ind(p1,i3+1) End If End If For i4 = 0 To 1 edge(i2,0) += 1 edge(i2,edge(i2,0)) = e(i4) Next End If i3 += 1 Loop sw = 0 i3 = 0 Do While i3 < len(k) and sw = 0 If i2 = ind(p2,i3) sw = 1 If i3 = 0 e(0) = ind(p2,len(k)-1) e(1) = ind(p2,1) Else If i3 = len(k)-1 e(0) = ind(p2,i3-1) e(1) = ind(p2,0) Else e(0) = ind(p2,i3-1) e(1) = ind(p2,i3+1) End If End If For i4 = 0 To 1 sw = 1 i5 = 1 Do While i5 <= edge(i2,0) and sw = 1 If edge(i2,i5) = e(i4) sw = 2 End If i5 += 1 Loop If sw = 1 edge(i2,0) += 1 edge(i2,edge(i2,0)) = e(i4) End If Next End If i3 += 1 Loop Next ' 交叉の実行 ' 出発点の決定 k1 = ind(p1,0) k2 = ind(p2,0) If edge(k1,0) = edge(k2,0) If rn.NextDouble() > 0.5 kk = k2 Else kk = k1 End If Else If edge(k1,0) < edge(k2,0) kk = k1 Else kk = k2 End If End If ind(k,0) = kk p = 1 Do While p < len(k) ' ノードの除去 For i2 = 0 To len(k)-1 sw = 0 If edge(i2,0) > 0 i3 = 1 Do While i3 <= 4 and sw = 0 If edge(i2,i3) = kk sw = 1 edge(i2,i3) = -1 edge(i2,0) -= 1 End If i3 += 1 Loop End If Next ' 次の現在ノードの選択 min = 10 num = 0 For i2 = 1 To 4 If edge(kk,i2) >= 0 k1 = edge(kk,i2) If edge(k1,0) >= 0 and edge(k1,0) < min num = 1 min = edge(k1,0) k0 = k1 Else If edge(k1,0) = min num += 1 End If End If End If Next If num > 1 k1 = Math.Floor(rn.NextDouble() * num) + 1 If k1 > num k1 = num End If k2 = 0 k0 = -1 i2 = 1 Do While i2 <= 4 and k0 < 0 If edge(kk,i2) >= 0 If edge(edge(kk,i2),0) = min k2 += 1 If k1 = k2 k0 = edge(kk,i2) End If End If End If i2 += 1 Loop Else If num <= 0 num = 0 For i2 = 0 To len(k)-1 If i2 <> kk and edge(i2,0) >= 0 num += 1 End If Next If num <= 0 Console.WriteLine("***error invalid data (C_edge)") Environment.Exit(1) Else k1 = Math.Floor(rn.NextDouble() * num) + 1 If k1 > num k1 = num End If k2 = 0 k0 = -1 i2 = 0 Do While i2 < len(k) and k0 < 0 If i2 <> kk and edge(i2,0) >= 0 k2 += 1 If k1 = k2 k0 = i2 End If End If i2 += 1 Loop End If End If End If edge(kk,0) = -1 ind(k,p) = k0 kk = k0 p += 1 Loop End If Next End Sub '***********************************************************' ' 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に' ' 同じ遺伝子のグループがない限り実行されない.たとえば' ' ***abcd** ' ' *cdab**** ' ' のような両親の時実行され,以下の4つの子供が生成され' ' る) ' ' ***cdab** ' ' *abcd**** ' ' ***badc** ' ' *dcba**** ' ' 最大,4*交叉回数*個体総数*(個体総数-1) 個の子 ' ' 供が生成される可能性があるので,子供の数としてこの値' ' 以上のデータを入力しておく必要がある. ' ' kosa : 交叉確率 ' ' count : 1つのペアーに対する交差回数 ' '***********************************************************' Sub C_sub(kosa As Double, count As Integer) Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim i4 As Integer Dim i5 As Integer Dim k1 As Integer Dim k2 As Integer Dim k3 As Integer Dim k4 As Integer Dim p1 As Integer Dim p2 As Integer Dim t11 As Integer Dim t12 As Integer = 0 Dim t21 As Integer Dim t22 As Integer = 0 Dim sw As Integer ' ' 初期設定とデータのチェック ' If (4*count*size*(size-1)) > max_ch Console.WriteLine("***error 子供が多すぎる (C_sub)") Environment.Exit(1) End If ' ' 交叉 ' For i1 = 0 To size-2 ' 親1 p1 = Position(i1) If p1 >= 0 For i2 = i1 To size-1 ' 親2 p2 = Position(i2) If p2 >= 0 ' 交叉しない場合 If rn.NextDouble() > kosa C_copy(2, 1, -1, 0.0, 0.0) ' 交叉する場合 Else ' 交叉回数の制御 For i3 = 0 To count-1 ' 交叉位置の決定(点の後ろで交叉) ' 親1の交叉位置 t11 = Math.Floor(rn.NextDouble() * len(p1)) If t11 > (len(p1)-1) t11 = len(p1) - 1 End If sw = 0 Do While sw = 0 t12 = Math.Floor(rn.NextDouble() * len(p1)) If t12 > (len(p1)-1) t12 = len(p1) - 1 End If If t12 <> t11 sw = 1 End If Loop If t11 > t12 k1 = t11 t11 = t12 t12 = k1 End If ' 親2の交叉位置 sw = 0 t21 = -1 i4 = 0 Do While i4 < len(p2) and t21 < 0 i5 = t11 Do While i5 <= t12 and t21 < 0 If ind(p2,i4) = ind(p1,i5) t21 = i4 End If i5 += 1 Loop i4 += 1 Loop If t21 >= 0 t22 = t21 + t12 - t11 If t22 < len(p2) sw = 1 i4 = t21 + 1 Do While i4 <= t22 and sw > 0 sw = 0 i5 = t11 Do While i5 <= t12 and sw = 0 If ind(p2,i4) = ind(p1,i5) sw = 1 End If i5 += 1 Loop i4 += 1 Loop End If End If ' 交叉の実行 If sw > 0 k1 = Position(-1) pi_w(k1) = 1 len(k1) = len(p1) k2 = Position(-1) pi_w(k2) = 1 len(k2) = len(p1) k3 = Position(-1) pi_w(k3) = 1 len(k3) = len(p2) k4 = Position(-1) pi_w(k4) = 1 len(k4) = len(p2) For i4 = 0 To t11-1 ind(k1,i4) = ind(p1,i4) ind(k2,i4) = ind(p1,i4) Next For i4 = t11 To t12 ind(k1,i4) = ind(p2,t21+i4-t11) ind(k2,i4) = ind(p2,t22-i4+t11) Next For i4 = t12+1 To len(p1)-1 ind(k1,i4) = ind(p1,i4) ind(k2,i4) = ind(p1,i4) Next For i4 = 0 To t21-1 ind(k3,i4) = ind(p2,i4) ind(k4,i4) = ind(p2,i4) Next For i4 = t21 To t22 ind(k3,i4) = ind(p1,t11+i4-t21) ind(k4,i4) = ind(p1,t12-i4+t21) Next For i4 = t22+1 To len(p2)-1 ind(k3,i4) = ind(p2,i4) ind(k4,i4) = ind(p2,i4) Next End If Next End If End If Next End If Next End Sub '************************************' ' 突然変異(対立遺伝子との置き換え) ' ' pr : 突然変異率 ' '************************************' Sub M_alle(pr As Double) Dim i1 As Integer Dim i2 As Integer Dim lid As Integer ' ' データのチェックと初期設定 ' If dup_a = 0 Console.WriteLine("***error 突然変異方法が不適当 (M_alle)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 For i2 = 0 To len(i1)-1 If rn.NextDouble() <= pr lid = Math.Floor(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l) If lid > allele_u lid = allele_u End If If lid <> ind(i1,i2) ind(i1,i2) = lid End If End If Next End If Next End Sub '********************************************************************' ' 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に ' ' 移動する) ' ' pr : 突然変異率 ' '********************************************************************' Sub M_move(pr As Double) Dim i1 As Integer Dim i2 As Integer Dim ld As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 位置の決定 ' ' p1 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If ' p2 sw = 0 Do While sw = 0 p2 = Math.Floor(rn.NextDouble() * len(i1)) If p2 >= len(i1) p2 = len(i1) - 1 End If If p2 <> p1 sw = 1 End If Loop ' ' 実行 ' If p2 > p1 ld = ind(i1,p2) For i2 = p2 To p1+1 Step -1 ind(i1,i2) = ind(i1,i2-1) Next ind(i1,p1) = ld Else ld = ind(i1,p2) For i2 = p2 To p1-2 ind(i1,i2) = ind(i1,i2+1) Next ind(i1,p1-1) = ld End If End If Next End Sub '******************************************************' ' 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '******************************************************' Sub M_inv(pr As Double, wd As Integer) Dim i1 As Integer Dim lid As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 区間の決定 ' If wd = 0 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If sw = 0 Do While sw = 0 p2 = Math.Floor(rn.NextDouble() * len(i1)) If p2 >= len(i1) p2 = len(i1) - 1 End If If p2 <> p1 sw = 1 End If Loop If p1 > p2 p = p1 p1 = p2 p2 = p End If Else p1 = len(i1) Do While p1 > len(i1)-2 p1 = Math.Floor(rn.NextDouble() * len(i1)) Loop p2 = p1 + wd - 1 If p2 >= len(i1) p2 = len(i1) - 1 End If End If ' ' 実行 ' sw = 0 Do While sw = 0 lid = ind(i1,p1) ind(i1,p1) = ind(i1,p2) ind(i1,p2) = lid p1 += 1 p2 -= 1 If p1 >= p2 sw = 1 End If Loop End If Next End Sub '********************************************************************' ' 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_scram(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim ld As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer = 0 Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 区間の決定 ' If wd = 0 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If sw = 0 Do While sw = 0 p2 = Math.Floor(rn.NextDouble() * len(i1)) If p2 >= len(i1) p2 = len(i1) - 1 End If If p2 <> p1 sw = 1 End If Loop If p1 > p2 p = p1 p1 = p2 p2 = p End If Else p1 = len(i1) Do While p1 > len(i1)-2 p1 = Math.Floor(rn.NextDouble() * len(i1)) Loop p2 = p1 + wd - 1 If p2 >= len(i1) p2 = len(i1) - 1 End If End If ' ' 実行 ' For i2 = p1 To p2 p = Math.Floor(rn.NextDouble() * (p2 - p1 + 1) + p1) If p > p2 p = p2 End If ld = ind(i1,i2) ind(i1,i2) = ind(i1,p) ind(i1,p) = ld Next End If Next End Sub '********************************************************************' ' 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし ' ' 重複部分はそのままとする) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_chg(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim ld As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer Dim p3 As Integer = 0 Dim p4 As Integer Dim sw As Integer For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' ' 区間等の決定((p1,p2)と(p3,p4)の入れ替え) ' ' p1 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If ' p3 sw = 0 Do While sw = 0 p3 = Math.Floor(rn.NextDouble() * len(i1)) If p3 >= len(i1) p3 = len(i1) - 1 End If If p3 <> p1 sw = 1 End If Loop ' 小さい方をp1,p2にする If p1 > p3 p = p1 p1 = p3 p3 = p End If ' p4, p2 If wd = 0 p4 = Math.Floor(rn.NextDouble() * (len(i1) - p3)) + p3 Else p4 = p1 + wd - 1 End If If p4 >= len(i1) p4 = len(i1) - 1 End If p2 = p1 + (p4 - p3) ' 重複部分のチェック If p2 >= p3 p = p3 - 1 p3 = p2 + 1 p2 = p p4 = p3 + (p2 - p1) End If ' ' 実行 ' p = p3 For i2 = p1 To p2 ld = ind(i1,i2) ind(i1,i2) = ind(i1,p) ind(i1,p) = ld p += 1 Next End If Next End Sub '********************************************************************' ' 突然変異(重複.2点間の遺伝子を他の位置にコピーする ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_dup(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim p As Integer Dim p1 As Integer Dim p2 As Integer Dim p3 As Integer = 0 Dim p4 As Integer Dim sw As Integer ' ' データのチェック ' If dup_a = 0 Console.WriteLine("***error 突然変異方法が不適当 (M_dup)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' 区間の決定((p1,p2)を(p3,p4)にコピー) ' p1 p1 = Math.Floor(rn.NextDouble() * len(i1)) If p1 >= len(i1) p1 = len(i1) - 1 End If ' p3 sw = 0 Do While sw = 0 p3 = Math.Floor(rn.NextDouble() * len(i1)) If p3 >= len(i1) p3 = len(i1) - 1 End If If p3 <> p1 sw = 1 End If Loop ' 区間を決める If p3 > p1 If wd = 0 p4 = Math.Floor(rn.NextDouble() * (len(i1) - p3)) + p3 Else p4 = p3 + wd - 1 End If If p4 >= len(i1) p4 = len(i1) - 1 End If p2 = p1 + (p4 - p3) Else If wd = 0 p2 = Math.Floor(rn.NextDouble() * (len(i1) - p1)) + p1 Else p2 = p1 + wd - 1 End If If p2 >= len(i1) p2 = len(i1) - 1 End If p4 = p3 + (p2 - p1) End If ' 実行 p = p4 For i2 = p2 To p1 Step -1 ind(i1,p) = ind(i1,i2) p -= 1 Next End If Next End Sub '****************************************************' ' 突然変異(摂動.値をある量だけ変化させる) ' ' pr : 突然変異率 ' ' method : =0 : 正規分布 ' ' =1 : 一様分布 ' ' m : 平均または一様分布の下限 ' ' s : 標準偏差または一様分布の上限 ' '****************************************************' Sub M_per(pr As Double, method As Integer, m As Double, s As Double) Dim w As Double Dim wd As Double = 0.0 Dim x1 As Double Dim i1 As Integer Dim i2 As Integer ' ' データのチェックと初期設定 ' If dup_a = 0 Console.WriteLine("***error 突然変異方法が不適当 (M_per)") Environment.Exit(1) End If If method > 0 wd = s - m End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 For i2 = 0 To len(i1)-1 If rn.NextDouble() <= pr If method = 0 w = norm_d(m, s) Else w = rn.NextDouble() * wd If rn.NextDouble() < 0.5 w = -w End If End If x1 = ind(i1,i2) + w If x1 > allele_u x1 = allele_u Else If x1 < allele_l x1 = allele_l End If End If ind(i1,i2) = Math.Floor(x1) End If Next End If Next End Sub '********************************************************************' ' 突然変異(挿入.ある長さの遺伝子を挿入する) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_ins(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim l As Integer Dim ld As Integer Dim p As Integer ' ' データのチェック ' If dup_a = 0 or min_len < 0 Console.WriteLine("***error 突然変異方法が不適当 (M_ins)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' 挿入位置の決定 p = Math.Floor(rn.NextDouble() * (len(i1)+1)) If p > len(i1) p = len(i1) End If ' 挿入する遺伝子長の決定 If wd = 0 l = Math.Floor(rn.NextDouble() * (max_len - len(i1) + 1)) else l = wd End If If l > max_len-len(i1) l = max_len - len(i1) Else If l <= 0 l = 1 End If End If ' 実行 ' 挿入場所の確保 If p < len(i1) For i2 = len(i1)+l-1 To p Step -1 ind(i1,i2) = ind(i1,i2-l) Next End If ' 挿入場所の遺伝子の決定 For i2 = p To p ld = Math.Floor(rn.NextDouble() * (allele_u - allele_l + 1) + allele_l) If ld > allele_u ld = allele_u End If ind(i1,i2) = ld Next len(i1) += l End If Next End Sub '********************************************************************' ' 突然変異(削除.ある長さの遺伝子を削除する) ' ' pr : 突然変異率 ' ' wd : >0 : 幅を固定 ' ' =0 : 幅をランダム ' '********************************************************************' Sub M_del(pr As Double, wd As Integer) Dim i1 As Integer Dim i2 As Integer Dim l As Integer Dim max As Integer Dim p As Integer ' ' データのチェック ' If dup_a = 0 or min_len < 0 Console.WriteLine("***error 突然変異方法が不適当 (M_del)") Environment.Exit(1) End If ' ' 実行 ' For i1 = 0 To size+max_ch-1 If pi_w(i1) = 1 and rn.NextDouble() <= pr ' 削除位置の決定 p = Math.Floor(rn.NextDouble() * len(i1)) If p >= len(i1) p = len(i1) - 1 End If ' 削除する遺伝子長の決定 If len(i1)-min_len < len(i1)-p max = len(i1) - min_len Else max = len(i1) - p End If If wd = 0 l = Math.Floor(rn.NextDouble() * max + 1) Else l = wd End If If l > max l = max End If ' 実行 For i2 = 0 To len(i1)-p-l-1 ind(i1,p+i2) = ind(i1,p+i2+l) Next len(i1) -= l End If Next End Sub '*******************************************************************' ' 淘汰(エリート・ルーレット選択) ' ' elite : エリートで残す個体数(default=0) ' ' s_method : ルーレット板の作成方法(default=1) ' ' =0 : 適応度をそのまま使用 ' ' =1 : 最小値からの差(ただし,α以下の場合はα) ' ' =2 : 評価値に順位をつけ,減少率βで線形化 ' ' s_bias : α,または,method=2の場合は初期値(default=0) ' ' s_step : β(default=1) ' '*******************************************************************' Sub S_roul(elite As Integer, s_method As Integer, s_bias As Double, s_step As Double) Dim count As Integer = 0 Dim i1 As Integer Dim i2 As Integer Dim i3 As Integer Dim k As Integer = 0 Dim max As Integer Dim n As Integer = 0 Dim p As Integer Dim sw As Integer ' ' 値のチェックと初期設定 ' If s_method <> 0 and s_method <> 2 s_method = 1 End If If elite > size Console.WriteLine("***error エリートで残す数が多すぎる (S_roul)") Environment.Exit(1) End If If s_method = 2 and s_step <= 0.0 s_step = 1.0 End If For i1 = 0 To size+max_ch-1 s_w(i1) = 0 Next ' ' 重複個体を削除 ' If dup_s = 0 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 0 For i2 = i1+1 To size+max_ch-1 If pi_w(i2) > 0 and len(i1) = len(i2) sw = 0 i3 = 0 Do While i3 < len(i1) and sw = 0 If ind(i1,i3) <> ind(i2,i3) sw = 1 End If i3 += 1 Loop If sw = 0 pi_w(i2) = 0 End If End If Next End If Next End If For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 n += 1 End If Next If n < 0 or dup_s = 0 and n < size Console.WriteLine("***error 残す個体がない (S_roul)") Environment.Exit(1) End If ' ' 淘汰して残す個体を選ぶ ' ' エリートの選択 sw = 0 Do While k < elite and k < n and sw = 0 max = -1 For i1 = 0 To size+max_ch-1 If pi_w(i1) > 1 and s_w(i1) = 0 If max < 0 max = i1 ElseIf pi(i1) > pi(max) max = i1 End If End If Next If max < 0 sw = 1 Else s_w(max) = 1 k += 1 End If Loop ' ルーレット選択 Do While count < size+max_ch and k < size p = Select_f(s_method, s_bias, s_step) If dup_s = 0 and s_w(p) > 0 count += 1 Else count = 0 s_w(p) += 1 k += 1 End If Loop ' 選択に失敗した場合の処理 If dup_s = 0 and k < size i1 = 0 Do While i1 < size+max_ch and k < size If pi_w(i1) > 1 and s_w(i1) = 0 s_w(i1) = 1 k += 1 End If i1 += 1 Loop End If ' 複数回選択されたものの処理 For i1 = 0 To size+max_ch-1 If s_w(i1) = 0 pi_w(i1) = 0 End If Next For i1 = 0 To size+max_ch-1 If s_w(i1) > 0 If s_w(i1) > 1 For i2 = 2 To s_w(i1) k = Position(-1) len(k) = len(i1) pi_w(k) = 2 pi(k) = pi(i1) For i3 = 0 To len(i1)-1 ind(k,i3) = ind(i1,i3) Next Next End If End If Next End Sub End Class '*******************' ' クラスKansuの定義 ' '*******************' Class Kansu Inherits Species ' クラス Species を継承 Private cv As Double ' 2進数を10進数の変換する係数 Private max_gen As Integer ' 最大世代交代数 Private kosa_m As Integer ' 交叉方法 ' =-1 : 交叉を使用しない ' =0 : 親のコピー ' =1 : 多点交叉 ' =2 : 一様交叉 ' =3 : 平均化交叉 Private kosa As Double ' 交叉確率 Private k_point As Integer ' 交差点の数(負の時は,1から-point間のランダム) Private k_vr As Integer ' =0 : 両親とも同じ位置で交叉 ' =1 : 両親が異なる位置で交叉(遺伝子長は可変) Private k_method As Integer ' 交叉の時の親の選択方法 ' =-1 : ランダム ' =0 : 適応度をそのまま使用 ' =1 : 最小値からの差(ただし,α以下の場合はα) ' =2 : 評価値に順位をつけ,減少率βで線形化 Private k_bias As Double ' α,または,method=2の場合は初期値 Private k_step As Double ' β Private mute_m As Integer ' 突然変異方法 ' =-1 : 突然変異を使用しない ' =0 : 対立遺伝子への置換 ' =1 : 移動 ' =2 : 逆位 ' =3 : スクランブル ' =4 : 転座 ' =5 : 重複 ' =6 : 摂動 Private mute As Double ' 突然変異率 Private wd As Integer ' 突然変異に使用する部分遺伝子長 Private m_mean As Double ' 摂動の平均値 Private m_std As Double ' 摂動の標準偏差 Private elite As Integer ' エリート選択で残す数 Private s_method As Integer ' ルーレット板の作成方法 ' =0 : 適応度をそのまま使用 ' =1 : 最小値からの差(ただし,α以下の場合はα) ' =2 : 評価値に順位をつけ,減少率βで線形化 Private s_bias As Double ' α,または,s_method=2の場合は初期値 Private s_step As Double ' β Private out_d As Integer ' 表示間隔 Private out_lvl As Integer ' 出力レベル ' =0 : 最終出力だけ ' n>0 : n世代毎に出力(負の時はファイル) Private out_m As Integer ' 出力方法 ' =0 : すべてを出力 ' =1 : 最大適応度の個体だけを出力 Private o_file As String ' 出力ファイル名 '*************************************' ' コンストラクタ ' ' name1 : Species定義ファイル名 ' ' name2 : TSP定義ファイル名 ' ' seed : 乱数の初期値 ' '*************************************' Public Sub New (name1 As String, name2 As String, seed As Integer) MyBase.new(name1, seed) ' 基底クラスのコンストラクタ Dim MS As Regex = New Regex("\s+") Dim inp As StreamReader = New StreamReader(name2) ' 基本データの入力 ' 1行目 Dim str() As String = MS.Split(inp.ReadLine().Trim()) out_lvl = Integer.Parse(str(1)) out_m = Integer.Parse(str(3)) ' 2行目 str = MS.Split(inp.ReadLine().Trim()) o_file = str(1) out_d = Integer.Parse(str(3)) ' 3行目 str = MS.Split(inp.ReadLine().Trim()) kosa_m = Integer.Parse(str(1)) kosa = Double.Parse(str(3)) k_point = Integer.Parse(str(5)) k_vr = Integer.Parse(str(7)) k_method = Integer.Parse(str(9)) k_bias = Double.Parse(str(11)) k_step = Double.Parse(str(13)) ' 4行目 str = MS.Split(inp.ReadLine().Trim()) mute_m = Integer.Parse(str(1)) mute = Double.Parse(str(3)) wd = Integer.Parse(str(5)) m_mean = Double.Parse(str(7)) m_std = Double.Parse(str(9)) ' 5行目 str = MS.Split(inp.ReadLine().Trim()) elite = Integer.Parse(str(1)) s_method = Integer.Parse(str(3)) s_bias = Double.Parse(str(5)) s_step = Double.Parse(str(7)) ' 6行目 str = MS.Split(inp.ReadLine().Trim()) max_gen = Integer.Parse(str(1)) inp.Close() cv = 1.0 / (Math.Pow(2.0, max_len) - 1.0) End Sub '************' ' 全体の制御 ' '************' Sub Control() Dim gen As Integer = 1 ' 初期集団の発生 Init_std() ' 評価 Adap() ' 画面表示 Console.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean) ' 出力 If Math.Abs(out_lvl) > 0 Output(gen) End If ' 世代交代 For gen = 2 To max_gen ' 交叉 Select Case kosa_m Case 0 C_copy(2, max_ch/2, k_method, k_bias, k_step) ' 親のコピー Case 1 C_point(kosa, k_point, k_vr, k_method, k_bias, k_step) ' 多点交叉 Case 2 C_uniform(kosa, k_method, k_bias, k_step) ' 一様交叉 Case 3 C_mean(kosa, k_method, k_bias, k_step) ' 平均化交叉 End Select ' 突然変異 Select Case mute_m Case 0 M_alle(mute) ' 対立遺伝子への置換 Case 1 M_move(mute) ' 移動 Case 2 M_inv(mute, wd) ' 逆位 Case 3 M_scram(mute, wd) ' スクランブル Case 4 M_chg(mute, wd) ' 転座 Case 5 M_dup(mute, wd) ' 重複 Case 6 M_per(mute, wd, m_mean, m_std) ' 摂動 End Select ' 適応度 Adap() ' 淘汰 S_roul(elite, s_method, s_bias, s_step) ' 表示 If (gen Mod out_d) = 0 Console.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean) End If If Math.Abs(out_lvl) > 0 If (gen Mod Math.Abs(out_lvl)) = 0 Output(gen) End If End If Next gen -= 1 Dim k1 As Integer = out_m out_m = 0 Console.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean) Output(gen) out_m = k1 End Sub '***************************' ' 結果の出力 ' ' gen : 現在の世代番号 ' '***************************' Sub Output(gen As Integer) Dim pr As Integer = -1 If out_lvl >= 0 Console.Write(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ") pr = Integer.Parse(Console.ReadLine()) End If If pr <> 0 Dim OUT As StreamWriter = new StreamWriter(o_file, true) ' 出力先の決定と評価値の出力 If pr < 0 Dim now1 As DateTime = DateTime.Now ' 現在時刻の獲得 OUT.WriteLine("***世代 " & gen & " 適応度 max " & max & " (" & max_n & ") mean " & mean & " 時間 " & now1) End If ' 詳細出力 Dim k As Integer = 0 For i1 As Integer = 0 To size+max_ch-1 If (pi_w(i1) > 1) and (out_m = 0 or out_m = 1 or i1 = max_n) If pr < 0 OUT.Write(i1 & " allele") For i2 As Integer = 0 To len(i1)-1 OUT.Write(" " & ind(i1,i2)) Next Dim x As Double = 0.0 Dim y As Double = 0.0 For i2 As Integer = len(i1)-1 To 0 Step -1 If ind(i1,i2) > 0 x += Math.Pow(2.0, y) End If y += 1.0 Next x *= cv OUT.WriteLine(" x " & x & " y " & pi(i1)) Else Console.Write(i1 & " allele") For i2 As Integer = 0 To len(i1)-1 Console.Write(" " & ind(i1,i2)) Next Dim x As Double = 0.0 Dim y As Double = 0.0 For i2 As Integer = len(i1)-1 To 0 Step -1 If ind(i1,i2) > 0 x += Math.Pow(2.0, y) End If y += 1.0 Next x *= cv Console.WriteLine(" x " & x & " y " & pi(i1)) End If If pr > 0 k += 1 If k = pr Console.ReadLine() k = 0 End If End If End If Next OUT.Close() End If End Sub '**************' ' 適応度の計算 ' '**************' Sub Adap() max = 0.0 max_n = -1 mean = 0.0 Dim n As Integer = 0 For i1 As Integer = 0 To size+max_ch-1 If pi_w(i1) = 1 Dim x As Double = 0.0 Dim y As Double = 0.0 For i2 As Integer = len(i1)-1 To 0 Step -1 If ind(i1,i2) > 0 x += Math.Pow(2.0, y) End If y += 1.0 Next x *= cv pi(i1) = Math.Sin(3.0*x) + 0.5 * Math.Sin(9.0*x) + Math.Sin(15.0*x+50.0) pi_w(i1) = 2 End If If pi_w(i1) > 0 mean += pi(i1) n += 1 If max_n < 0 or pi(i1) > max max = pi(i1) max_n = i1 End If End If Next mean /= n End Sub End Class End Module //------------------ケーススタディデータ(data_cf.txt)------ /* 3 data1_f.txt data2_f.txt data1_f.txt data2_f.txt data1_f.txt data2_f.txt */ //------------------Species記述データ(data1_f.txt)--------- /* 対立遺伝子上限 1 対立遺伝子下限 0 最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1 遺伝子の重複 1 個体の重複(同じ染色体の個体) 0 集団サイズ 20 子供 20 */ //------------------Function記述データ(data2_f.txt)-------- /* 出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0 出力ファイル名 out1.txt 表示間隔 1 交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1 突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0 エリート 2 方法 1 バイアス 0 ステップ 1 最大世代交代数 200 */
情報学部 | 菅沼ホーム | 目次 | 索引 |