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