如果这个博客帮到了你,不要忘记给个赞!
运行环境为:win10 + MS-MPI v10.1.2 + python 3.7 + mpi4py
1. 代码设计思路
总体设计思路:以0号进程作为主进程,除了处理自己负责的计算任务之外,还需要对其他进程处理完的数据进行汇总和归一化。计算分为两个部分:1. 首先是遍历所有的行数,在遍历的过程中将矩阵的每一行处理为上三角的形式。N行矩阵一共遍历N轮,算法复杂度为 O(n2)。每个子进程处理完自己的行数后,将结果发送给0号进程。0号进程得到汇总数据后进行对角线元素归一化处理,然后将新的矩阵广播给其他进程进行下一步处理;2. 每个进程收到广播后将上三角矩阵中分配给自己的行数进行消元处理,将消元后的结果再次发送给0号进程,0号进程汇集成单位矩阵形式得出最终结果,消元过程中迭代时间复杂度为O(n) 。因此,总体时间复杂度为 ,最终的时间复杂度为 ,比串行计算要求的 要小一个数量级。
具体流程如下图:
图 1 程序流程图
2. 实现代码
import numpy as np
from mpi4py import MPI
class Config(object):
# Matrix = [[1, 2, 3], [2, 3, 5], [3, 4, 6], [3, 4, 7]]
# answer = [[6], [10], [13], [14]]
Matrix = [[1, 2, 3, 4], [2, 3, 5, 8], [3, 4, 6, 0], [3, 4, 7, 33]]
answer = [[6], [10], [13], [14]]
opt = Config()
data = np.concatenate([np.array(opt.Matrix), np.array(opt.answer)], 1)
row = data.shape[0]
column = data.shape[1]
comm = MPI.COMM_WORLD
comm_rank = comm.Get_rank()
comm_size = comm.Get_size()
if comm_rank == 0: # 0号进程打印矩阵信息
print('代求矩阵为: \n', data)
# 将矩阵转为上三角的形式
for step in range(row):
if comm_rank == 0:
data = comm.bcast(data, root=0)
for a in range(step+1, row):
if a % comm_size == comm_rank: # 0号线程单独处理
data[a, :] = data[a, :] - data[a, step]/data[step, step] * data[step, :] # 把矩阵转为上三角形式
for a in range(step, row-1):
if (a+1) % comm_size == 0: # 不需要接收0号线程的消息
pass
else:
data[a+1, :] = comm.recv(source=(a+1) % comm_size)
else:
data = comm.bcast(None, root=0)
for a in range(step+1, row):
if a % comm_size == comm_rank: # 对每个线程进行任务分配
data[a, :] = data[a, :] - data[a, step]/data[step, step] * data[step, :] # 把矩阵转为上三角形式
comm.send(data[a, :], dest=0)
if comm_rank == 0: # 0号进程打印矩阵信息,此时矩阵全部转为上三角
print('上三角化后的结果: \n', data)
# 消元求解
if comm_rank == 0:
# 对已经转为上三角的矩阵进行主对角线元素归一化
for a in range(row):
data[a, :] = data[a, :]/data[a, a]
data = comm.bcast(data, root=0)
# 0号进程处理自己分配到的的任务
for a in range(row):
if a % comm_size == comm_rank:
if a == row-1: # 矩阵最后一行归一化后不再需要处理
pass
else:
for b in range(a, row-1):
data[a, :] = data[a, :] - data[a, b+1] * data[b+1, :]
pass
# 0号进程收集其他进程处理好的数据,更新到data数组里
for a in range(row-1):
if (a + 1) % comm_size == 0:
pass
else:
data[a + 1, :] = comm.recv(source=(a + 1) % comm_size)
print('高斯消元后的结果\n', data)
print('解向量为: \n', data[:, column-1])
# 其他进程将各自分配到的任务进行消元求解
else:
data = comm.bcast(None, root=0)
for a in range(row):
if a % comm_size == comm_rank:
if a == row-1: # 矩阵最后一行归一化后不再需要处理,但是依然发送消息
comm.send(data[a, :], dest=0)
else:
for b in range(a, row-1):
data[a, :] = data[a, :] - data[a, b+1] * data[b+1, :]
comm.send(data[a, :], dest=0)
3. 运行结果
直接利用anaconda里的prompt运行这个脚本,前提是电脑已经安装过msmpi,如果没有,下载网址在这里:
https://www.microsoft.com/en-us/download/details.aspx?id=100593
下载完成后别忘了将安装目录下的Bin目录添加到电脑的环境变量里,不然没法使用mpiexec指令
环境配置教程参考这个:
https://mp.csdn.net/console/editor/html/106365965
安装好后anaconda里使用这个命令安装mpi4py:
pip install mpi4py
然后使用prompt进入脚本所在的目录,输入以下指令完成运行结果:
mpiexec /np 4 python test.py