invert.c
资源名称:mpi.zip [点击查看]
上传用户:hhyinxing
上传日期:2013-09-10
资源大小:833k
文件大小:7k
源码类别:
并行计算
开发平台:
Unix_Linux
- #include "stdio.h"
- #include "stdlib.h"
- #include "mpi.h"
- #define a(x,y) a[x*M+y]
- #define A(x,y) A[x*M+y]
- #define B(x,y) B[x*M+y]
- #define floatsize sizeof(float)
- #define intsize sizeof(int)
- int M, N;
- float *A, *B;
- double starttime;
- double time1;
- double time2;
- int my_rank;
- int p;
- int m;
- float* a;
- float* f;
- MPI_Status status;
- /*
- * 函数名:fatal
- * 功能:程序出现严重错误时中止并给出错误信息;
- * 输入:message为存储错误信息的字符数组;
- */
- void fatal(char *message)
- {
- printf("%sn", message);
- exit(1);
- }
- /*
- * 函数名:Environment_Finalize
- * 功能:清理程序所占用的内存空间;
- * 输入:a,f均为储存浮点数的数组,分别用于存放主行各元素和
- * 各进程将要处理的数据;
- */
- void Environment_Finalize(float *a, float *f)
- {
- free(a);
- free(f);
- }
- /*
- * 函数名:matrix_init
- * 功能:矩阵初始化。包括分配存储空间,从输入文件中读入数据;
- * 输入:无输入参数;
- * 输出:无返回值;
- */
- void matrix_init()
- {
- int i, j;
- FILE* fdA;
- if (my_rank==0)
- {
- /* starttime记录开始分配数据的时刻 */
- starttime=MPI_Wtime();
- fdA=fopen("dataIn.txt", "r");
- fscanf(fdA, "%d %d", &M, &N);
- /* 如果矩阵不是方阵,则报错 */
- if(M!=N)
- {
- puts("The input is error!");
- exit(0);
- }
- A=(float *)malloc(floatsize*M*M);
- for(i=0; i<M; i ++)
- for(j=0; j<M; j++)
- fscanf(fdA, "%f", A+i*M+j);
- fclose(fdA);
- B=(float *)malloc(floatsize*M*M);
- }
- /* 广播M(矩阵的维数)给所有进程 */
- MPI_Bcast(&M, 1, MPI_INT, 0, MPI_COMM_WORLD);
- }
- /*
- * 函数名:maxtrix_partition
- * 功能:矩阵划分。0号进程对矩阵A进行行交叉划分,将划分后的子矩阵
- * 分别传送给1至p-1号进程。
- */
- void matrix_partition()
- {
- int i, j, i1, i2;
- /* 各进程为主行元素建立发送和接收缓冲区 */
- f=(float*)malloc(sizeof(float)*M);
- /* 分配至各进程的子矩阵大小为m*M */
- a=(float*)malloc(sizeof(float)*m*M);
- if (a==NULL || f==NULL)
- fatal("allocate errorn");
- /* 0号进程拷贝相应数据到其子矩阵a */
- if (my_rank==0)
- {
- for(i=0; i<m; i++)
- for(j=0; j<M; j++)
- a(i,j)=A(i*p,j);
- /* 0号进程采用行交叉划分将矩阵A划分为m*M的p块子矩阵,依次发送给1至p-1号进程 */
- for(i=0; i<m*p; i++)
- if ((i%p)!=0)
- {
- i1=i%p;
- i2=i/p+1;
- if (i<M)
- MPI_Send(&A(i,0), M, MPI_FLOAT, i1, i2, MPI_COMM_WORLD);
- else
- MPI_Send(&A(0,0), M, MPI_FLOAT, i1, i2, MPI_COMM_WORLD);
- }
- }
- else
- { /* 其它进程接收各自的子矩阵数据 */
- for(i=0; i<m; i++)
- MPI_Recv(&a(i,0), M, MPI_FLOAT, 0, i+1, MPI_COMM_WORLD, &status);
- }
- }
- /*
- * 函数名:broadcast_j
- * 功能:编号为j的进程广播主行元素
- * 输入:i为每个进程正在处理的子矩阵的行号,
- * j为主元素所在的进程的编号,
- * v为主元素(在矩阵A中)的行号;
- */
- void broadcast_j(int i, int j, int v)
- {
- int k;
- /* j号进程广播主行元素 */
- if (my_rank==j)
- {
- a(i,v)=1/a(i,v);
- for(k=0; k<M; k++)
- {
- if (k!=v)
- a(i,k)=a(i,k)*a(i,v); /* 处理主行各元素 */
- f[k]=a(i,k);
- }
- /* 将变换后的主行元素(存于数组f中)广播到所有进程中 */
- MPI_Bcast(f, M, MPI_FLOAT, my_rank, MPI_COMM_WORLD);
- }
- else
- {
- /* 其余进程接收广播来的主行元素存于数组f中 */
- MPI_Bcast(f, M, MPI_FLOAT, j, MPI_COMM_WORLD);
- }
- }
- /*
- * 函数名:row_transform
- * 功能:各进程对其子矩阵的各行进行初等行变换
- * 输入:i为每个进程正在处理的子矩阵的行号,
- * j为主元素所在的进程的编号,
- * v为主元素(在矩阵A中)的行号;
- */
- void row_transform(int i, int j, int v)
- {
- int k, w;
- /* 编号不为j的进程利用主行对其m行行向量做行变换 */
- if (my_rank!=j)
- {
- /* 处理非主行、非主列元素 */
- for(k=0; k<m; k++)
- {
- for(w=0; w<M; w++)
- if(w!=v)
- a(k,w)=a(k,w)-f[w]*a(k,v);
- a(k,v)=-f[v]*a(k,v);
- }
- }
- /* 发送主行数据的进程利用主行对其主行之外的m-1行行向量做行变换 */
- if (my_rank==j)
- {
- for(k=0; k<m; k++)
- if (k!=i)
- {
- for(w=0; w<M; w++)
- if (w!=v)
- /* 处理主行所在的进程中的其它元素 */
- a(k,w)=a(k,w)-f[w]*a(k,v);
- /* 处理主列元素 */
- a(k,v)=-f[v]*a(k,v);
- }
- }
- }
- /*
- * 函数名:matrix_inverse
- * 功能:得到输入矩阵的逆矩阵,结果存入矩阵B中;
- */
- void matrix_inverse()
- {
- int i, j, k;
- /* 0号进程将自己子矩阵a中的各行数据存入B */
- if (my_rank==0)
- for(i=0; i<m; i++)
- for(j=0; j<M; j++)
- B(i*p,j)=a(i,j);
- /* 0号进程从其余各进程中接收子矩阵a,得到经过变换的逆矩阵B */
- if (my_rank!=0)
- {
- for(i=0; i<m; i++)
- for(j=0; j<M; j++)
- MPI_Send(&a(i,j), 1, MPI_FLOAT, 0, my_rank, MPI_COMM_WORLD);
- }
- else
- {
- for(i=1; i<p; i++)
- for(j=0; j<m; j++)
- for(k=0; k<M; k++)
- {
- MPI_Recv(&a(j,k), 1, MPI_FLOAT, i, i, MPI_COMM_WORLD, &status);
- if ((j*p+i)<M)
- B((j*p+i),k)=a(j,k);
- }
- }
- }
- /*
- * 函数名:print_result
- * 功能:输出计算结果和时间统计;
- */
- void print_result()
- {
- FILE* fdOut;
- int i, j;
- /* 0号进程将运算结果写入目标文件 */
- if(my_rank==0)
- {
- fdOut=fopen("dataOut.txt", "w");
- fprintf(fdOut, "Input of file "dataIn.txt"n");
- fprintf(fdOut, "%dt%dn", M, M);
- for(i=0;i<M;i++)
- {
- for(j=0; j<M; j++)
- fprintf(fdOut, "%ft", A(i,j));
- fprintf(fdOut, "n");
- }
- fprintf(fdOut, "nOutput of Matrix A's inversionn");
- for(i=0; i<M; i++)
- {
- for(j=0; j<M; j++)
- fprintf(fdOut, "%ft", B(i,j));
- fprintf(fdOut, "n");
- }
- /* 0号进程将时间统计写入目标文件 */
- fprintf(fdOut, "n");
- fprintf(fdOut, "Whole running time = %f secondsn", time2-starttime);
- fprintf(fdOut, "Distribute data time = %f secondsn", time1-starttime);
- fprintf(fdOut, "Parallel compute time = %f secondsn", time2-time1);
- fprintf(fdOut, "Parallel Process number = %dn", p);
- fclose(fdOut);
- }
- }
- /*
- * 函数名: main
- * 功能:各个进程的主函数,处理程序的输入,计算并输出结果
- * 输入:argc为命令行参数个数;
- * argv为每个命令行参数组成的字符串数组。
- * 输出:返回0代表程序正常结束;
- */
- int main(int argc, char **argv)
- {
- int i, j, group_size;
- int v;
- MPI_Init(&argc, &argv);
- MPI_Comm_size(MPI_COMM_WORLD, &group_size);
- MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
- /* p为进程数 */
- p=group_size;
- matrix_init();
- /* m为每个进程需要处理的子矩阵行数 */
- m=M/p;
- if (M%p!=0) m++;
- matrix_partition();
- /* time1记录计算开始的时间 */
- time1=MPI_Wtime();
- /* 各个进程(当前编号为j的)轮流广播自己的第i行作为主行元素 */
- for(i=0; i<m; i++)
- for(j=0; j<p; j++)
- {
- v=i*p+j;
- if (v<M)
- {
- broadcast_j(i,j,v);
- row_transform(i,j,v);
- }
- }
- matrix_inverse();
- /* time2为计算结束的时刻 */
- time2=MPI_Wtime();
- print_result();
- MPI_Finalize();
- Environment_Finalize(a,f);
- return(0);
- free(A);
- free(B);
- }