题目要求
假设有 p p p个进程, A A A是 n ∗ n n*n n∗n阶矩阵, n = m ∗ p n=m*p n=m∗p,设计并行计算 A x + b Ax+b Ax+b的算法,其中 A A A是按列分块存放在每个进程中,亦即每个进程中的 A A A是 n ∗ m n*m n∗m阶矩阵,每个进程中 x x x是 m m m维向量, b b b存放在第 0 0 0个进程中,最终计算结果存放在 x x x中。
- (20分) 并行算法简述;
- (45分)写出只使用
MPI_Send
和MPI_Recv
或者MPI_Sendrecv
函数实现并行计算 A x + b Ax+b Ax+b的子程序,计算结果存放在 x x x中; - (35分)当原始矩阵A的元素 a i j = i + j , x = 1 , − 1 , 1 , − 1 , . . . . . . a_{ij}=i+j,x={1, -1, 1, -1, ......} aij=i+j,x=1,−1,1,−1,......, b = x b=x b=x。请写一个主程序对上述子程序进行验证,并给出 p = 4 p=4 p=4, m = 11 m=11 m=11时的计算结果。
代码
MPI初始化函数
void mybegin(int *argc, char ***argv, MPI_Comm *comm, int *np, int *iam)
{
MPI_Init(argc, argv);
//复制通讯址
MPI_Comm_dup(MPI_COMM_WORLD, comm);
MPI_Comm_size(MPI_COMM_WORLD, np);
MPI_Comm_rank(MPI_COMM_WORLD, iam);
}
数据初始化函数
#define lda 100
void init_A(int m, int n, int A[][lda], int iam)
{
for (int i = 0; i < n; i++)
for (int j = iam * m; j < iam * m + m; j++)
A[i][j] = i + j;
}
void init_x(int m, int x[], int iam)
{
for (int i = iam * m; i < iam * m + m; i++)
if (i % 2 == 0)
x[i] = 1;
else
x[i] = -1;
}
void init_b(int n, int b[], int iam)
{
if (iam != 0)
return;
for (int i = 0; i < n; i++)
if (i % 2 == 0)
b[i] = 1;
else
b[i] = -1;
}
计算函数
void mul(int row, int col, int m, int A[][lda], int x[], int c[])
{
for (int i = 0; i < row; i++)
{
c[i] = 0;
for (int j = col; j < col + m; j++)
c[i] += A[i][j] * x[j];
}
}
void matmul(int np, int iam, MPI_Comm comm, int m, int n, int A[][lda], int x[],
int b[], int c[])
{
MPI_Status st;
mul(n, iam * m, m, A, x, c); //先乘,结果放在c中
if (iam == 0)
{
for (int i = 0; i < n; i++)
{
x[i] = c[i] + b[i]; //自己进程的计算结果与b的和
}
for (int i = 1; i < np; i++)
{
MPI_Recv(b, n, MPI_INT, i, 0, comm, &st); //接收其他进程计算结果
for (int j = 0; j < n; j++)
{
x[j] += b[j]; //结果更新
}
}
for (int i = 1; i < np; i++)
MPI_Send(x, n, MPI_INT, i, 1, comm); //将汇总之后的结果发送给其他进程
}
else
{
MPI_Send(c, n, MPI_INT, 0, 0, comm); //计算结果发给0号进程汇总
MPI_Recv(x, n, MPI_INT, 0, 1, comm, &st); //接收汇总之后的结果
}
}
主函数
int main(int argc, char *argv[])
{
MPI_Comm comm;
int np, iam;
// A保存矩阵,x保存m维度向量,b保存向量,c用来算保存计算结果
int m, n, A[lda][lda], x[lda], b[lda], c[lda];
mybegin(&argc, &argv, &comm, &np, &iam);
m = 11;
n = 44;
init_A(m, n, A, iam);
init_x(m, x, iam);
init_b(n, b, iam);
matmul(np, iam, comm, m, n, A, x, b, c);
if (iam == 0)
{
printf(" \n Proc %d ans = ", iam);
for (int i = 0; i < n; i++)
{
printf(" %d,", x[i]);
}
printf("\n");
}
MPI_Finalize();
return 0;
}
结果
Proc 0 ans = -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23, -21, -23,