invert.c
上传用户:hhyinxing
上传日期:2013-09-10
资源大小:833k
文件大小:7k
源码类别:

并行计算

开发平台:

Unix_Linux

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "mpi.h"
  4. #define a(x,y) a[x*M+y]
  5. #define A(x,y) A[x*M+y]
  6. #define B(x,y) B[x*M+y]
  7. #define floatsize sizeof(float)
  8. #define intsize sizeof(int)
  9. int M, N;
  10. float *A, *B;
  11. double starttime;
  12. double time1;
  13. double time2;
  14. int my_rank;
  15. int p;
  16. int m;
  17. float* a;
  18. float* f;
  19. MPI_Status status;
  20. /*
  21.  * 函数名:fatal
  22.  * 功能:程序出现严重错误时中止并给出错误信息;
  23.  * 输入:message为存储错误信息的字符数组;
  24.  */
  25. void fatal(char *message)
  26. {
  27.     printf("%sn", message);
  28.     exit(1);
  29. }
  30. /*
  31.  * 函数名:Environment_Finalize
  32.  * 功能:清理程序所占用的内存空间;
  33.  * 输入:a,f均为储存浮点数的数组,分别用于存放主行各元素和
  34.  *       各进程将要处理的数据;
  35.  */
  36. void Environment_Finalize(float *a, float *f)
  37. {
  38.     free(a);
  39.     free(f);
  40. }
  41. /*
  42.  * 函数名:matrix_init
  43.  * 功能:矩阵初始化。包括分配存储空间,从输入文件中读入数据;
  44.  * 输入:无输入参数;
  45.  * 输出:无返回值;
  46.  */
  47. void matrix_init()
  48. {
  49.     int i, j;
  50.     FILE* fdA;
  51.     if (my_rank==0)
  52.     {
  53.         /* starttime记录开始分配数据的时刻 */
  54.         starttime=MPI_Wtime();
  55.         fdA=fopen("dataIn.txt", "r");
  56.         fscanf(fdA, "%d %d", &M, &N);
  57.         /* 如果矩阵不是方阵,则报错 */
  58.         if(M!=N)
  59.         {
  60.             puts("The input is error!");
  61.             exit(0);
  62.         }
  63.         A=(float *)malloc(floatsize*M*M);
  64.         for(i=0; i<M; i ++)
  65.             for(j=0; j<M; j++)
  66.                 fscanf(fdA, "%f", A+i*M+j);
  67.         fclose(fdA);
  68.         B=(float *)malloc(floatsize*M*M);
  69.     }
  70.     /* 广播M(矩阵的维数)给所有进程 */
  71.     MPI_Bcast(&M, 1, MPI_INT, 0, MPI_COMM_WORLD);
  72. }
  73. /*
  74.  * 函数名:maxtrix_partition
  75.  * 功能:矩阵划分。0号进程对矩阵A进行行交叉划分,将划分后的子矩阵
  76.  *       分别传送给1至p-1号进程。
  77.  */
  78. void matrix_partition()
  79. {
  80.     int i, j, i1, i2;
  81.     /* 各进程为主行元素建立发送和接收缓冲区 */
  82.     f=(float*)malloc(sizeof(float)*M);
  83.     /* 分配至各进程的子矩阵大小为m*M */
  84.     a=(float*)malloc(sizeof(float)*m*M);
  85.     if (a==NULL || f==NULL)
  86.         fatal("allocate errorn");
  87.      /* 0号进程拷贝相应数据到其子矩阵a */
  88.     if (my_rank==0)
  89.     {
  90.         for(i=0; i<m; i++)
  91.             for(j=0; j<M; j++)
  92.                 a(i,j)=A(i*p,j);
  93.         /* 0号进程采用行交叉划分将矩阵A划分为m*M的p块子矩阵,依次发送给1至p-1号进程 */
  94.         for(i=0; i<m*p; i++)
  95.             if ((i%p)!=0)
  96.         {
  97.             i1=i%p;
  98.             i2=i/p+1;
  99.             if (i<M)
  100.                 MPI_Send(&A(i,0), M, MPI_FLOAT, i1, i2, MPI_COMM_WORLD);
  101.             else
  102.                 MPI_Send(&A(0,0), M, MPI_FLOAT, i1, i2, MPI_COMM_WORLD);
  103.         }
  104.     }
  105.     else
  106.     {                                             /* 其它进程接收各自的子矩阵数据 */
  107.         for(i=0; i<m; i++)
  108.             MPI_Recv(&a(i,0), M, MPI_FLOAT, 0, i+1, MPI_COMM_WORLD, &status);
  109.     }
  110. }
  111. /*
  112.  * 函数名:broadcast_j
  113.  * 功能:编号为j的进程广播主行元素
  114.  * 输入:i为每个进程正在处理的子矩阵的行号,
  115.  *       j为主元素所在的进程的编号,
  116.  *       v为主元素(在矩阵A中)的行号;
  117.  */
  118. void broadcast_j(int i, int j, int v)
  119. {
  120.     int k;
  121.     /* j号进程广播主行元素 */
  122.     if (my_rank==j)
  123.     {
  124.         a(i,v)=1/a(i,v);
  125.         for(k=0; k<M; k++)
  126.         {
  127.             if (k!=v)
  128.                 a(i,k)=a(i,k)*a(i,v);             /* 处理主行各元素 */
  129.             f[k]=a(i,k);
  130.         }
  131.         /* 将变换后的主行元素(存于数组f中)广播到所有进程中 */
  132.         MPI_Bcast(f, M, MPI_FLOAT, my_rank, MPI_COMM_WORLD);
  133.     }
  134.     else
  135.     {
  136.         /* 其余进程接收广播来的主行元素存于数组f中 */
  137.         MPI_Bcast(f, M, MPI_FLOAT, j, MPI_COMM_WORLD);
  138.     }
  139. }
  140. /*
  141.  * 函数名:row_transform
  142.  * 功能:各进程对其子矩阵的各行进行初等行变换
  143.  * 输入:i为每个进程正在处理的子矩阵的行号,
  144.  *       j为主元素所在的进程的编号,
  145.  *       v为主元素(在矩阵A中)的行号;
  146.  */
  147. void row_transform(int i, int j, int v)
  148. {
  149.     int k, w;
  150.     /* 编号不为j的进程利用主行对其m行行向量做行变换 */
  151.     if (my_rank!=j)
  152.     {
  153.         /* 处理非主行、非主列元素 */
  154.         for(k=0; k<m; k++)
  155.         {
  156.             for(w=0; w<M; w++)
  157.                 if(w!=v)
  158.                     a(k,w)=a(k,w)-f[w]*a(k,v);
  159.             a(k,v)=-f[v]*a(k,v);
  160.         }
  161.     }
  162.     /* 发送主行数据的进程利用主行对其主行之外的m-1行行向量做行变换 */
  163.     if (my_rank==j)
  164.     {
  165.         for(k=0; k<m; k++)
  166.             if (k!=i)
  167.         {
  168.             for(w=0; w<M; w++)
  169.                 if (w!=v)
  170.                     /* 处理主行所在的进程中的其它元素 */
  171.                     a(k,w)=a(k,w)-f[w]*a(k,v);
  172.             /* 处理主列元素 */
  173.             a(k,v)=-f[v]*a(k,v);
  174.         }
  175.     }
  176. }
  177. /*
  178.  * 函数名:matrix_inverse
  179.  * 功能:得到输入矩阵的逆矩阵,结果存入矩阵B中;
  180.  */
  181. void matrix_inverse()
  182. {
  183.     int i, j, k;
  184.     /* 0号进程将自己子矩阵a中的各行数据存入B */
  185.     if (my_rank==0)
  186.         for(i=0; i<m; i++)
  187.             for(j=0; j<M; j++)
  188.                 B(i*p,j)=a(i,j);
  189.     /* 0号进程从其余各进程中接收子矩阵a,得到经过变换的逆矩阵B */
  190.     if (my_rank!=0)
  191.     {
  192.         for(i=0; i<m; i++)
  193.             for(j=0; j<M; j++)
  194.                 MPI_Send(&a(i,j), 1, MPI_FLOAT, 0, my_rank, MPI_COMM_WORLD);
  195.     }
  196.     else
  197.     {
  198.         for(i=1; i<p; i++)
  199.             for(j=0; j<m; j++)
  200.                 for(k=0; k<M; k++)
  201.                 {
  202.                     MPI_Recv(&a(j,k), 1, MPI_FLOAT, i, i, MPI_COMM_WORLD, &status);
  203.                     if ((j*p+i)<M)
  204.                         B((j*p+i),k)=a(j,k);
  205.                 }
  206.     }
  207. }
  208. /*
  209.  * 函数名:print_result
  210.  * 功能:输出计算结果和时间统计;
  211.  */
  212. void print_result()
  213. {
  214.     FILE* fdOut;
  215.     int i, j;
  216.      /* 0号进程将运算结果写入目标文件 */
  217.     if(my_rank==0)
  218.     {
  219.         fdOut=fopen("dataOut.txt", "w");
  220.         fprintf(fdOut, "Input of file "dataIn.txt"n");
  221.         fprintf(fdOut, "%dt%dn", M, M);
  222.         for(i=0;i<M;i++)
  223.         {
  224.             for(j=0; j<M; j++)
  225.                 fprintf(fdOut, "%ft", A(i,j));
  226.             fprintf(fdOut, "n");
  227.         }
  228.         fprintf(fdOut, "nOutput of Matrix A's inversionn");
  229.         for(i=0; i<M; i++)
  230.         {
  231.             for(j=0; j<M; j++)
  232.                 fprintf(fdOut, "%ft", B(i,j));
  233.             fprintf(fdOut, "n");
  234.         }
  235.         /* 0号进程将时间统计写入目标文件 */
  236.         fprintf(fdOut, "n");
  237.         fprintf(fdOut, "Whole running time    = %f secondsn", time2-starttime);
  238.         fprintf(fdOut, "Distribute data time  = %f secondsn", time1-starttime);
  239.         fprintf(fdOut, "Parallel compute time = %f secondsn", time2-time1);
  240.         fprintf(fdOut, "Parallel Process number = %dn", p);
  241.         fclose(fdOut);
  242.     }
  243. }
  244. /*
  245.  * 函数名: main
  246.  * 功能:各个进程的主函数,处理程序的输入,计算并输出结果
  247.  * 输入:argc为命令行参数个数;
  248.  *       argv为每个命令行参数组成的字符串数组。
  249.  * 输出:返回0代表程序正常结束;
  250.  */
  251. int main(int argc, char **argv)
  252. {
  253.     int i, j, group_size;
  254.     int v;
  255.     MPI_Init(&argc, &argv);
  256.     MPI_Comm_size(MPI_COMM_WORLD, &group_size);
  257.     MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  258.     /* p为进程数 */
  259.     p=group_size;
  260.     matrix_init();
  261.     /* m为每个进程需要处理的子矩阵行数 */
  262.     m=M/p;
  263.     if (M%p!=0) m++;
  264.     matrix_partition();
  265.     /* time1记录计算开始的时间 */
  266.     time1=MPI_Wtime();
  267.     /* 各个进程(当前编号为j的)轮流广播自己的第i行作为主行元素 */
  268.     for(i=0; i<m; i++)
  269.         for(j=0; j<p; j++)
  270.     {
  271.         v=i*p+j;
  272.         if (v<M)
  273.         {
  274.             broadcast_j(i,j,v);
  275.             row_transform(i,j,v);
  276.         }
  277.     }
  278.     matrix_inverse();
  279.     /* time2为计算结束的时刻 */
  280.     time2=MPI_Wtime();
  281.     print_result();
  282.     MPI_Finalize();
  283.     Environment_Finalize(a,f);
  284.     return(0);
  285.     free(A);
  286.     free(B);
  287. }