[ create a new paste ] login | about

Link: http://codepad.org/hTWnVRm3    [ raw code | fork ]

C, pasted on Dec 6:
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<time.h>

static int result_min=999; /* 過去の試行で得られた解(999の場合:解未発見)*/

/*	個体の定義

	表現型は2分木の解(=根が有する2つの要素)である。
		root[0]には左要素、root[1]には右要素がセットされる。

	2分木は「親を持たない(parentless)ノードを2つ選択し、親ノードを1つ生成する」作業を
	9回繰り返すことにより完成すると考える。
	
		・初期状態で存在する parentless なノードは10個である。
		・作成されたばかりの親ノードは parentless である。
		・その子となった2つのノードは parentless ではなくなる。
		・親ノードが1つ生成されるたびに parentless なノードの総数は1つ減る。

	i番目の親ノードを生成する際、parentless なノードのうち、M番目を左枝の子
	ノード、N番目を右枝の子ノードとする。
	これを遺伝子1として idensi1[i][0]=M, idensi1[i][1]=N に定義する。
	
	i番目の親ノードを生成する際、親ノードがA型となる場合は0、B型となる場合は1を
	遺伝子2として idensi2[i] にセットする。*/

struct ST_KOTAI {
	int root[2];
	int idensi1[9][2];
	int idensi2[9];
} ;

/*	集団の定義:個体数は KOTAI_MAX(5の倍数)とする。*/

#define KOTAI_MAX 10000
static struct ST_KOTAI kotai[KOTAI_MAX];

/* 遺伝子から表現型を生成 */

static void root_make(struct ST_KOTAI *stk)
{
	int parentless_node[10][2]={{2,5},{3,1},{4,2},{4,2},{5,3},{3,6},{6,2},{9,2},{8,1},{7,4}};
	int i,j,k;
	
	/* 2分木の構築

		parentless_node[]は親を持たないノードの配列であり、初期値は固定である。
		parentless_node[][0]は左要素、parentless_node[][1]は右要素を意味する。

		親ノードが1つ生成されるたびに
		・その子に選ばれた2つのノードが parentless_node[] から削除される。
		・親となったノードが parentless_node[] に追加される。

		親ノードが9回生成されると、根のノードが残る。*/

	for(i=0;i<9;i++) { /* 親ノードを9回生成する */
		int child_l[2],child_r[2],parent[2];

		/*	idensi1[i]に基づいて parentless_node[] より2つ選択し、要素の値をコピーする。*/

		child_l[0]=parentless_node[ stk->idensi1[i][0] ][0]; /* 左要素@左枝 */
		child_l[1]=parentless_node[ stk->idensi1[i][0] ][1]; /* 右要素@左枝 */
		child_r[0]=parentless_node[ stk->idensi1[i][1] ][0]; /* 左要素@右枝 */
		child_r[1]=parentless_node[ stk->idensi1[i][1] ][1]; /* 右要素@右枝 */

		/* indensi2[i]に基づいて、親ノードの要素を計算する。*/

		if(0==stk->idensi2[i]) { /* A型 */
			parent[0]=child_l[0]+child_r[0]; /* 左要素は加算 */ 
			parent[1]=(child_l[1]>child_r[1])?child_l[1]:child_r[1]; /* 右要素は大きい方 */
		} else { /* B型 */
			parent[0]=(child_l[0]>child_r[0])?child_l[0]:child_r[0]; /* 左要素は大きい方 */
			parent[1]=child_l[1]+child_r[1]; /* 右要素は加算 */
		}

		/* 子に選ばれたノードを parentless_node[] から削除する。*/
		j=0;
		for(k=0;k<10-i;k++) {
			if((k!=stk->idensi1[i][0])&&(k!=stk->idensi1[i][1])) {
				parentless_node[j][0]=parentless_node[k][0];
				parentless_node[j][1]=parentless_node[k][1];
				j++;
			}
		}

		/* 親となったノードを parentless_node[] の末尾に追加する。*/
		parentless_node[j][0]=parent[0];
		parentless_node[j][1]=parent[1];
	}

	/* 根となったノードの要素を保存する。*/
	stk->root[0]=parentless_node[0][0];
	stk->root[1]=parentless_node[0][1];
}

/*	初期集団の発生:遺伝子をランダムに生成 */

static void kotai_init(void)
{
	int i,j;

	srand((unsigned)time(NULL)); /* 乱数の初期化 */

	for(i=0;i<KOTAI_MAX;i++) {
		for(j=0;j<9;j++) { /* j番目の遺伝子を決定する */
			/* idensi1[j]の値域は0~(9-j) */
			kotai[i].idensi1[j][0]=rand()%(10-j);
			while(kotai[i].idensi1[j][0]==(kotai[i].idensi1[j][1]=(rand()%(10-j))));
			/* idensi2[j]の値域は0~1 */
			kotai[i].idensi2[j]=rand()%2;
		}

		/* 表現型を生成 */
		root_make(kotai+i);
	}
}

/*	子孫の生成

	親から継承した18個の遺伝子(indesi1[9],idensi2[9])のうち
	どれか1をランダムに選択し、ランダムに変更する。これを9回繰り返す。

	※回数(=9)は適当に決めた。
	※回数を大きく設定するほど、子孫の遺伝子が大きく変化する。*/

static void sison(struct ST_KOTAI *stk_parent,struct ST_KOTAI *stk_child)
{
	int i,j,k;
	
	memcpy(stk_child,stk_parent,sizeof(struct ST_KOTAI)); /* 親をコピー */

	j=rand()%10; /* 0~9 */

	for(i=0;i<j;i++) { /* idensi1 をj回ランダムに変更 */
		k=rand()%9;
		stk_child->idensi1[k][0]=rand()%(10-k);
		while(stk_child->idensi1[k][0]==(stk_child->idensi1[k][1]=rand()%(10-k)));
	}

	for(i=j;i<9;i++) { /* idensi2 を(9-j)回ランダムに変更 */
		k=rand()%9;
		stk_child->idensi2[k]=rand()%2;
	}

	/* 表現型を生成 */
	root_make(stk_child);
}


/*	評価関数 */

static int kotai_compare(const struct ST_KOTAI *a,const struct ST_KOTAI *b)
{
	/* 制約条件「右要素が15以下」をどちらか一方だけが満たしている場合
		条件を満たしている側を最も高く評価する */

	if((15>=a->root[1])&&(15<b->root[1]))
		return -1;
	else if((15<a->root[1])&&(15>=b->root[1]))
		return 1;

	/* 	左要素が小さい側を高く評価する。
		左要素が同じ場合、右要素が小さい側を高く評価する */

	if(a->root[0]<b->root[0])
		return -1;
	else if(a->root[0]>b->root[0])
		return 1;
	else if(a->root[1]<b->root[1])
		return -1;
	else if(a->root[1]>b->root[1])
		return 1;

	return 0;
}

/*	評価の実施

	同じ評価が連続する世代数が SEDAI_MAX に達した場合0を返す。
	そうでない場合は1を返す。*/

#define SEDAI_MAX 200

static int hyoka(void)
{
	static int count=0; /* 同じ評価が連続した世代数 */

	/* 評価関数にて評価し、適応順に並べ替える */
	qsort(kotai,KOTAI_MAX,sizeof(struct ST_KOTAI),kotai_compare);

	if((result_min>kotai[0].root[0])&&(15>=kotai[0].root[1])) { /* 制約条件を満たす、新しい解が得られた場合 */
		count=0;
		result_min=kotai[0].root[0];
	} else /* それ以外の場合 */
		count++;

	if(count<SEDAI_MAX) /* 同じ解が連続する世代数が SEDAI_MAX 未満の場合、1を返す */
		return 1;

	return 0; /* 評価終了 */
}

int main()
{
	int i=0,j;

	kotai_init(); /* 初期集団の生成 */

	for(i=0;hyoka();i++) { /* 評価 */

		if(999==result_min)
			printf("第%d世代: 不明\n",i+1);
		else
			printf("第%d世代: %d\n",i+1,result_min);

		/* 上位20%の親から子孫を作り出す */

		for(j=0;j<KOTAI_MAX/5;j++) {
			sison(kotai+j,kotai+j+1*KOTAI_MAX/5);
			sison(kotai+j,kotai+j+2*KOTAI_MAX/5);
			sison(kotai+j,kotai+j+3*KOTAI_MAX/5);
			sison(kotai+j,kotai+j+4*KOTAI_MAX/5);
		}
	}

	if(999==result_min)
		printf("第%d世代: 不明\n",i+1);
	else
		printf("第%d世代: %d\n",i+1,result_min);

	return 0;
}


Create a new paste based on this one


Comments: