简介
细胞自动机(又称元胞自动机),名字虽然很深奥,但是它的行为却是非常美妙的。所有这些怎样实现的呢?我们可以把计算机中的宇宙想象成是一堆方格子构成的封闭空间,尺寸为N的空间就有NN个格子。而每一个格子都可以看成是一个生命体,每个生命都有生和死两种状态,如果该格子生就显示蓝色,死则显示白色。每一个格子旁边都有邻居格子存在,如果我们把33的9个格子构成的正方形看成一个基本单位的话,那么这个正方形中心的格子的邻居就是它旁边的8个格子。
每个格子的生死遵循下面的原则:
1. 如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。
2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;
3. 在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)
实现思路
将全局矩阵分解为大小相等的(工作)块,这样我们就可以实现生命的游戏。
初始化:从文件中读取数据:一个包含游戏初始状态的m×n矩阵。
为了与其他处理器通信,我设置了一个局部矩阵和一个全局矩阵。局部矩阵是一种混合状态。对于处理器0,它可以从局部矩阵中获得全局矩阵。
MPI并行实现
#include <stdio.h>
#include <string.h>
#include "mpi.h"
#include <stdlib.h>
static int MAX_M;
static int MAX_N;
static int epoch;
static int DEAD=0;
static int ALIVE=1;
double exe_time;
int size, myid, s, ver, row, col, dir;
int *local_matrix = NULL;
int *tmpmatrix = NULL;
int *global_matrix = NULL;
int *newglobal_matrix = NULL;
MPI_Request requests[4];
MPI_Status status[4];
FILE * matrix;
void display(int *local_matrix){
int i, j;
printf("%10c", ' ');
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
for (i = 0; i < MAX_M; i++){
printf("\n%10c", ' ');
for (j = 0; j < MAX_N; j++)
if (local_matrix[i * MAX_N + j] == ALIVE)
printf("+");
else
printf("-");
}
printf("\n%10c\n", ' ');
}
int adj8(int neighbor, int row, int col){
int res;
if(neighbor == 2){
return local_matrix[row * MAX_N + col];
}else if(neighbor == 3){
return ALIVE;
}else{
return DEAD;
}
}
int main(int argc,char *argv[]){
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
ver = MAX_M / size;
epoch= atoi(argv[1]);
MAX_M= atoi(argv[2]);
MAX_N= atoi(argv[3]);
local_matrix = (int*)malloc(sizeof(int) * (ver+2) * MAX_N);
tmpmatrix = (int*)malloc(sizeof(int) * (ver+2) * MAX_N);
for (row = 0; row < ver+2; row++) {
for (col = 0; col < MAX_N; col++) {
local_matrix[row*MAX_N+col] = DEAD;
tmpmatrix[row*MAX_N+col] = DEAD;
}
}
//Initialization
if (myid == 0) {
int i;
global_matrix = (int*)malloc(sizeof(int) * MAX_M * MAX_N);
newglobal_matrix = (int*)malloc(sizeof(int) * MAX_M * MAX_N);
if((matrix = fopen("matrix.txt","r"))==NULL){
printf("the file can not open.");
return -1;
}
for(row = 0; row < MAX_M; row++){
for(col = 0; col < MAX_N; col++){
fscanf(matrix,"%d ", &global_matrix[row*MAX_N + col]);
}
fscanf(matrix,"\n");
}
memcpy(&local_matrix[MAX_N], &global_matrix[0], ver * MAX_N * sizeof(int));
for (dir = 1; dir < size; dir++) {
MPI_Send(&global_matrix[dir*ver*MAX_N], ver * MAX_N, MPI_INT, dir, 1, MPI_COMM_WORLD);
}
display(global_matrix);
} else {
//For each processor, there is a local matrix.
MPI_Recv(&local_matrix[MAX_N], ver * MAX_N, MPI_INT, 0, 1, MPI_COMM_WORLD, status);
}
exe_time = -MPI_Wtime();
for (int count=0; count<epoch;count++){
int req_id = 0;
if (myid == 0) {
MPI_Isend(&local_matrix[(ver)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
MPI_Irecv(&local_matrix[(ver+1)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
printf("\n");
display(local_matrix);
} else {
MPI_Irecv(local_matrix, MAX_N, MPI_INT, myid - 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
MPI_Isend(&local_matrix[(ver)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
MPI_Irecv(&local_matrix[(ver+1)*MAX_N], MAX_N, MPI_INT, myid + 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
MPI_Isend(&local_matrix[MAX_N], MAX_N, MPI_INT, myid - 1, 1, MPI_COMM_WORLD, &requests[req_id++]);
}
MPI_Waitall(req_id, requests, status);
for (row = 1; row < ver+1; row+=1){
for (col = 0; col < MAX_N; col++){
int neighbor = 0, c, r;
for (r = row - 1; r <= row + 1; r++)
for (c = col - 1; c <= col + 1; c++){
if (c < 0 || c >= MAX_N) continue;
if (local_matrix[r * MAX_N + c] == ALIVE) neighbor++;
}
if (local_matrix[row * MAX_N + col] == ALIVE)
neighbor--;
tmpmatrix[row * MAX_N + col] = adj8(neighbor, row, col);
}
}
for (row = 1; row < ver+1; row+=1){
for (col = 0; col < MAX_N; col++){
local_matrix[row * MAX_N + col] = tmpmatrix[row * MAX_N + col];
}
}
}
if (myid == 0) {
exe_time += MPI_Wtime();
printf("Time: %lf \n", exe_time);
memcpy(global_matrix, &local_matrix[MAX_N], ver * MAX_N * sizeof(int));
for (dir = 1; dir < size; dir++) {
MPI_Recv(&global_matrix[dir*ver*MAX_N], ver*MAX_N, MPI_INT, dir, 1, MPI_COMM_WORLD, status);
}
printf("Last Status:\n");
display(global_matrix);
}
else {
MPI_Send(&local_matrix[MAX_N], ver * MAX_N, MPI_INT, 0, 1, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
输出示例
来源:OmegaXYZ丨xyjisaw
写在最后:对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!
C语言C++编程学习交流圈子,QQ群:739386924【点击进入】微信公众号:C语言编程学习基地
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
C语言基础视频分享: