卒論
参考サイト:MPI並列プログラミング
#include <stdio.h>
#include <stdlib.h> /* rand() */
#include <time.h> /* srand() */
#include "mpi.h"
#define NODE 50 /* 都市の数 */
#define MAX_DIST 30 /* 都市間の距離の最大値 */
#define GENOM 200 /* 遺伝子数 */
#define LIMIT 100000 /* 計算回数 */
#define EVOLUTION 1 /* 突然変異発生確率[%] */
#define MIG_INTERVAL 1000 /* 移住間隔[世代] */
#define MIG_RATE 15 /* 移住率[%] */
#define DEBUG1 0 /* 関数確認用 */
#define DEBUG2 0 /* 経路が正しいかどうか確認 */
#define WRITEFILE 1 /* ファイルへの書き込み用の出力 */
typedef struct {
double dist[NODE]; /* town[now].dist[go] */
int flag; /* 訪問確認用旗 */
} TOWN;
TOWN town[NODE];
typedef struct {
double distance; /* 距離 */
int route[NODE+1]; /* 経路 */
int flag; /* 旗 */
} RESULT;
RESULT result[GENOM];
int champ = 0;
double fast = NODE * MAX_DIST;
void func(void); /* 母集団生成 */
void makelist(void); /* 都市間の距離リスト作成 */
void tournament(int rank); /* 淘汰 */
void calc_dist(RESULT *res); /* 距離計算 */
void cross(void); /* 交叉 */
void variation(int np); /* 突然変異 */
void migrate(int rank, int np,
MPI_Status *status); /* 移住 */
/* main **************************************************************/
int main(int argc, char **argv) {
int i, j, k, min, sec;
int start, end;
time_t t1,t2;
int rank, np; /* ランク、端末数 */
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &np);
double fast_rank[np], fast_all;
makelist();
int distribution[GENOM][NODE+1];
/* --- 親 (rank=0) --- */
if (rank == 0)
{
start = time(&t1); /* 開始時間取得 */
srand((unsigned)time(NULL));
func(); /* 母集団初期化 */
/* 母集団の配分 */
for (i = 1; i < np; i++) { //i: 端末(rank)
for (j = 0; j < GENOM; j++) { //j: 遺伝子数
for (k = 0; k < NODE+1; k++) { //k: 経路
distribution[j][k] = result[j].route[k];
}
}
MPI_Send(distribution, GENOM*(NODE+1), MPI_INT,
i, 99, MPI_COMM_WORLD);
}
}
/* --- 子 (rank!=0) --- */
else
{
/* 母集団の受け取り */
MPI_Recv(distribution, GENOM*(NODE+1), MPI_INT,
0, 99, MPI_COMM_WORLD, &status);
for (i = 0; i < GENOM; i++) { //i: 遺伝子数
for (j = 0; j < NODE+1; j++) { //j: 経路
result[i].route[j] = distribution[i][j];
}
calc_dist(&result[i]); //距離計算
}
srand((unsigned)time(NULL));
}
/* ループ */
i = 0;
while (i < LIMIT) {
cross(); /* 交叉 */
tournament(rank);
if ((rand() % 100) < EVOLUTION) {
variation(np); /* 突然変異 */
tournament(rank); /* 淘汰 */
}
i++;
if (i % MIG_INTERVAL == 0){
/* 結果表示 */
if (rank == 0)
{
fast_all = fast;
for (j = 1; j < np; j++) {
MPI_Recv(&fast_rank[j], 1, MPI_DOUBLE, j,
50, MPI_COMM_WORLD, &status);
if (fast_all > fast_rank[j])
fast_all = fast_rank[j];
}
#if WRITEFILE
printf("%d\t%6.2f\n", i, fast_all);
//printf("%6.2f\n", fast_all);
#endif
}
else
{
MPI_Send(&fast, 1, MPI_DOUBLE, 0,
50, MPI_COMM_WORLD);
}
if (np-1)
migrate(rank, np, &status); /* 移住 */
}
} //loop end
#if WRITEFILE
usleep(1000*rank*100);
printf("%2d> %6.2f: ", rank, result[champ].distance);
for (i = 0; i < NODE+1; i++) {
printf("%2d ", result[champ].route[i]);
}
puts("");
#endif
if (rank == 0)
{
fast_all = fast;
for (i = 1; i < np; i++) {
MPI_Recv(&fast_rank[i], 1, MPI_INT, i,
50, MPI_COMM_WORLD, &status);
if (fast_all > fast_rank[i])
fast_all = fast_rank[i];
}
printf("the shortest distance: %.2f\n", fast_all);
end = time(&t2); /* 終了時間取得 */
min = end - start;
sec = min / 60;
min -= sec * 60;
#if WRITEFILE
usleep(1000*np*100);
printf("exec time;;; %d:%02d\n", sec, min);
#endif
}
else
{
MPI_Send(&fast, 1, MPI_INT, 0,
50, MPI_COMM_WORLD);
}
MPI_Finalize(); /* MPI終了 */
}
/* func **************************************************************/
void func() {
#if DEBUG1
puts("--func");
#endif
int i, j, go;
for (i = 0; i < GENOM; i++)
{
result[i].distance = 0;
result[i].route[0] = 0;
result[i].route[NODE] = 0;
for (j = 1; j < NODE; j++) {
town[j].flag = 0;
}
town[0].flag = 1;
for (j = 1; j < NODE; j++) {
do {
go = rand() % (NODE-1) + 1;
} while (town[go].flag); //do-while end
result[i].route[j] = go;
town[go].flag++;
} //for(j) end
calc_dist(&result[i]); /* 距離計算 */
} //for(i) end
#if DEBUG1
puts("--func end");
#endif
/* calc_dist *********************************************************/
void calc_dist(RESULT *res) {
int i, now, go;
/* 経路が正しいかどうか確認 */
#if DEBUG2
double judge = 0, dist_judge = 0;
for (i = 1; i < NODE; i++) {
judge += res->route[i];
dist_judge += i;
}
if (judge != dist_judge) {
puts("route error!");
exit(1);
}
#endif
res->distance = 0;
now = 0;
for (i = 1; i < NODE+1; i++) {
go = res->route[i];
res->distance += town[now].dist[go];
now = go;
}
}
/* tournament ********************************************************/
void tournament(int rank) {
#if DEBUG1
printf("--tournament %d\n", rank);
#endif
int i, n, x;
for (i = 0; i < GENOM/2; i++)
{
n = i;
x = GENOM-1-i;
if (result[n].distance > result[x].distance) {
n = x;
result[i] = result[n]; /* 代入 */
}
if (result[n].distance < result[champ].distance)
champ = n;
}
if (fast > result[champ].distance){
fast = result[champ].distance;
#if WRITEFILE==0
/* 記録表示 */
printf("%2d> %6.2f: ", rank, result[champ].distance);
for (i = 0; i < NODE+1; i++) {
printf("%2d ", result[champ].route[i]);
}
putchar('\n');
#endif
}
#if DEBUG1
printf("--tournament %d end\n", rank);
#endif
}
/* cross *************************************************************/
/* 部分交叉 */
void cross() {
#if DEBUG1
puts("--cross");
#endif
int i, j, k, l, a, b, x;
int tmp1, tmp2;
int flag1[NODE], flag2[NODE]; /* parent1,parent2用旗 */
RESULT parent1, parent2;
for (i = 0; i < GENOM/2; i+=2)
{
/* 交叉するペアを選択 */
a = rand() % (GENOM/2);
do {
b = rand() % (GENOM/2);
} while (a == b);
parent1 = result[a];
parent2 = result[b];
/* 旗初期化 */
for (j = 0; j < NODE; j+=2) {
flag1[j] = 1; flag1[j+1] = 1;
flag2[j] = 1; flag2[j+1] = 1;
}
/* 距離の短いルートは交叉しないようにする */
for (j = 0; j < NODE; j++) {
if (town[parent1.route[j]].dist[parent1.route[j+1]] < 2) {
flag1[j] = 0; flag1[j+1] = 0;
}
if (town[parent2.route[j]].dist[parent2.route[j+1]] < 2) {
flag2[j] = 0; flag2[j+1] = 0;
}
}
/* 交叉 */
x = rand() % (NODE-1) + 1; /* 切れ目 */
for (j = x; j < NODE; j++) {
tmp1 = parent1.route[j];
tmp2 = parent2.route[j];
if (flag1[j] && flag2[j]) {
for (k = 1; k < NODE; k++) {
if ((parent1.route[k] == tmp2) && k!=j && flag1[k]) {
parent1.route[j] = tmp2; flag1[j] = 0;
parent1.route[k] = tmp1; flag1[k] = 0;
}
if ((parent2.route[k] == tmp1) && k!=j && flag2[k]) {
parent2.route[j] = tmp1; flag2[j] = 0;
parent2.route[k] = tmp2; flag2[k] = 0;
}
} //for(k) end
} //if(j) end
} //for(j) end
/* 距離計算 */
calc_dist(&parent1);
calc_dist(&parent2);
l = GENOM/2+i;
result[l] = parent1;
result[l+1] = parent2;
} //for(i) end
#if DEBUG1
puts("--cross end");
#endif
}
/* variation *********************************************************/
/* 突然変異 --位置移動 */
void variation(int np) {
#if DEBUG1
puts("--variation");
#endif
int i, j, k, l;
int x, y, z, tmp;
RESULT parent;
/* 旗初期化 */
for (i = 0; i < GENOM; i++) {
result[i].flag = 0;
}
k = rand()%10+1;
for (i = 0; i < GENOM*k/100; i++)
{
do {
j = rand() % GENOM;
} while (result[j].flag);
result[j].flag = 1;
parent = result[j];
//l = rand()%15+1;
l = 1;
for (j = 0; j < l; j++) {
do {
x = rand() % (NODE-1) + 1;
} while (town[x-1].dist[x] < 2);
do {
y = rand() % (NODE-1) + 1;
} while (x == y || town[y].dist[y+1] < 2);
if (x > y) { /* x < y の関係にする */
tmp = x;
x = y;
y = tmp;
}
/* 位置移動 */
tmp = parent.route[y];
for (z = y; z > x; z--) {
parent.route[z] = parent.route[z-1];
}
parent.route[x] = tmp;
}
calc_dist(&parent); /* 距離計算 */
result[GENOM-i] = parent;
} //for(i) end
#if DEBUG1
puts("--variaion end");
#endif
}
/* migrate ***********************************************************/
/* 移住 */
void migrate(int rank, int np, MPI_Status *status) {
#if DEBUG1
printf("%d migrate\n", rank);
#endif
int i, j, b, x;
int flag[GENOM] = {0};
int a; /* 遺伝子数 x MIG_RATE[%] */
int immigrant[a][NODE+1];
a = GENOM*MIG_RATE/100;
/* 移住者を決める */
for (i = 0; i < a; i++) {
do {
x = rand() % GENOM;
} while (flag[x]);
flag[x] = 1;
for (j = 0; j < NODE+1; j++) {
immigrant[i][j] = result[x].route[j];
}
}
b = a * (NODE+1); /* 送信するデータの数 */
/* 偶数rank 送信->受信 */
if (rank%2 == 0)
{
/* 送信 */
MPI_Send(immigrant, b, MPI_INT, rank+1,
10, MPI_COMM_WORLD);
/* 受信 */
if (rank == 0) {
MPI_Recv(immigrant, b, MPI_INT, np-1,
20, MPI_COMM_WORLD, status);
}
else {
MPI_Recv(immigrant, b, MPI_INT, rank-1,
20, MPI_COMM_WORLD, status);
}
/* 受信データ格納 */
for (i = 0; i < a; i++) {
do {
x = rand()%(GENOM/2)+(GENOM/2);
} while (flag[x]);
flag[x] = 1;
for (j = 0; j < NODE+1; j++) {
result[x].route[j] = immigrant[i][j];
}
calc_dist(&result[x]);
}
}
/* 奇数rank 受信->送信 */
else
{
/* 受信 */
MPI_Recv(immigrant, b, MPI_INT, rank-1,
10, MPI_COMM_WORLD, status);
/* 受信データ格納 */
for (i = 0; i < a; i++) {
do {
x = rand()%(GENOM/2)+(GENOM/2);
} while (flag[x]);
flag[x] = 1;
for (j = 0; j < NODE+1; j++) {
result[x].route[j] = immigrant[i][j];
}
calc_dist(&result[x]);
}
/* 送信 */
if (rank == np-1) {
MPI_Send(immigrant, b, MPI_INT, 0,
20, MPI_COMM_WORLD);
}
else {
MPI_Send(immigrant, b, MPI_INT, rank+1,
20, MPI_COMM_WORLD);
}
}
/* 移住者を決める */
for (i = 0; i < a; i++) {
do {
x = rand() % GENOM;
} while (flag[x]);
flag[x] = 1;
for (j = 0; j < NODE+1; j++) {
immigrant[i][j] = result[x].route[j];
}
}
/* 偶数rank 受信->送信 */
if (rank%2 == 0)
{
/* 受信 */
MPI_Recv(immigrant, b, MPI_INT, rank+1,
30, MPI_COMM_WORLD, status);
/* 受信データ格納 */
for (i = 0; i < a; i++) {
do {
x = rand()%(GENOM/2)+(GENOM/2);
} while (flag[x]);
flag[x] = 1;
for (j = 0; j < NODE+1; j++) {
result[x].route[j] = immigrant[i][j];
}
calc_dist(&result[x]);
}
/* 送信 */
if (rank == 0) {
MPI_Send(immigrant, b, MPI_INT, np-1,
40, MPI_COMM_WORLD);
}
else {
MPI_Send(immigrant, b, MPI_INT, rank-1,
40, MPI_COMM_WORLD);
}
}
/* 奇数rank 送信->受信 */
else
{
/* 送信 */
MPI_Send(immigrant, b, MPI_INT, rank-1,
30, MPI_COMM_WORLD);
/* 受信 */
if (rank == np-1) {
MPI_Recv(immigrant, b, MPI_INT, 0,
40, MPI_COMM_WORLD, status);
}
else {
MPI_Recv(immigrant, b, MPI_INT, rank+1,
40, MPI_COMM_WORLD, status);
}
/* 受信データ格納 */
for (i = 0; i < a; i++) {
do {
x = rand()%(GENOM/2)+(GENOM/2);
} while (flag[x]);
flag[x] = 1;
for (j = 0; j < NODE+1; j++) {
result[x].route[j] = immigrant[i][j];
}
calc_dist(&result[x]);
}
}
tournament(rank);
}
/* makelist **********************************************************/
リストは別(参考サイト参照)
for (i = 0; i < NODE; i++) {
for (j = 0; j < NODE; j++) {
town[i].dist[j] = list[i][j];
}
}
}