Программа умножения матрицы на вектор

Результатом умножения матрицы на вектор является вектор результата. Для решения задачи используется алгоритм, в котором один процесс (главный) координирует работу других процессов (подчиненных). Для наглядности единая программа матрично-векторного умножения разбита на три части: общую часть , код главного процесса и код подчиненного процесса .

В общей части программы описываются основные объекты задачи: матрица А, вектор b, результирующий вектор с, определяется число процессов (не меньше двух). Задача разбивается на две части: главный процесс (master) и подчиненные процессы. В задаче умножения матрицы на вектор единица работы, которую нужно раздать процессам, состоит из скалярного произведения строки матрицы A на вектор b. Знаком ! отмечены комментарии.

 

program main

use mpi

integer MAX_ROWS, MAX_COLS, rows, cols

parameter (MAX_ROWS = 1000, MAX_COLS = 1000)

! матрица А, вектор b, результирующий вектор с

double precision a(MAX_ROWS,MAX_COLS), b(MAX_COLS), с(MAX_ROWS)

double precision buffer (MAX_COLS), ans /* ans – имя результата*/

integer myid, master, numprocs, ierr, status (MPI_STATUS_SIZE)

integer i, j, numsent, sender, anstype, row /* numsent – число посланных строк,

sender – имя процесса-отправителя, anstype – номер посланной строки*/

call MPI_INIT( ierr )

call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )

call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )

! главный процесс – master

master = 0

! количество строк и столбцов матрицы А

rows = 100

cols = 100

if ( myid .eq. master ) then

! код главного процесса

else

! код подчиненного процесса

endif

call MPI_FINALIZE(ierr)

stop

end

 

Код главного процесса. Единицей работы подчиненного процесса является умножение строки матрицы на вектор.

! инициализация А и b

do 20 j = 1, cols

b(j) = j

do 10 i = 1, rows

a(i,j) = i

10 continue

20 continue

numsent = 0

! посылка b каждому подчиненному процессу

call MPI_BCAST(b, cols, MPI_DOUBLE_PRECISION, master,

MPI_COMM_WORLD, ierr)

! посылка строки каждому подчиненному процессу; в TAG номер строки = i

do 40 i = 1,min(numprocs-l, rows)

do 30 j = I, cols

buffer(j) = a(i,j)

30 continue

call MPI_SEND(buffer, cols, MPI_DOUBLE_PRECISION, i, i,

MPI_COMM_WORLD, ierr)

numsent = numsent + l

40 continue

! прием результата от подчиненного процесса

do 70 i = 1, rows

! MPI_ANY_TAG – указывает, что принимается любая строка

call MPI_RECV(ans, 1, MPI_DOUBLE_PRECISION, MPI_ANY_SOURCE,

MPI_ANY_TAG, MPI_COMM_WORLD, status, ierr)

sender = status (MPI_SOURCE)

anstype = status (MPI_TAG)

! определяем номер строки

c(anstype) = ans

if (numsent .lt. rows) then

! посылка следующей строки

do 50 j = 1, cols

buffer(j) = a(numsent+l, j)

50 continue

call MPI_SEND (buffer, cols, MPI_DOUBLE_PRECISION, sender,

numsent+l, MPI_COMM_WORLD, ierr)

numsent = numsent+l

else

! посылка признака конца работы

call MPI_SEND(MPI_BOTTQM, 0, MPI_DOUBLE_PRECISION,sender,

0, MPI_COMM_WORLD, ierr)

endif

70 continue

 

Сначала главный процесс передает вектор b в каждый подчиненный про-

цесс, затем пересылает одну строку матрицы A в каждый подчиненный процесс.

Главный процесс, получая результат от очередного подчиненного процесса, пе-

редает ему новую работу. Цикл заканчивается, когда все строки будут розданы

и получены результаты.

При передаче данных из главного процесса в параметре tagуказывается

номер передаваемой строки. Этот номер после вычисления произведения вме-

сте с результатом будет отправлен в главный процесс, чтобы главный процесс

знал, где размещать результат.

Подчиненные процессы посылают результаты в главный процесс и пара-

метр MPI_ANY_TAGв операции приема главного процесса указывает, что

главный процесс принимает строки в любой последовательности. Параметр

statusобеспечивает информацию, относящуюся к полученному сообщению. В

языке Fortran это – массив целых чисел размера MPI_STATUS_SIZE. Аргу-

мент SOURCEсодержит номер процесса, который послал сообщение, по этому

адресу главный процесс будет пересылать новую работу. Аргумент TAGхра-

нит номер обработанной строки, что обеспечивает размещение полученного ре-

зультата. После того как главной процесс разослал все строки матрицы А, на

запросы подчиненных процессов он отвечает сообщением с отметкой 0.

Код подчиненного процесса .

! прием вектора b всеми подчиненными процессами

call MPI_BCAST(b, cols, MPI_DOUBLE_PRECISION, master,

MPI_COMM_WORLD, ierr)

! выход, если процессов больше количества строк матрицы

if (numprocs .gt. rows) goto 200

! прием строки матрицы

90 call MPI_RECV(buffer, cols, MPI_DOUBLE_PRECISION, master,

MPI_ANY_TAG, MPI_COMM_WORLD, status, ierr)

if (status (MPI_TAG) .eq. 0) then go to 200

! конец работы

else

row = status (MPI_TAG)

! номер полученной строки

ans = 0.0

do 100 i = 1, cols

! скалярное произведение векторов

ans = ans+buffer(i)*b(i)

100 continue

! передача результата головному процессу

call MPI_SEND(ans,1,MPI_DOUBLE_PRECISION,master,row,

MPI_COMM_WORLD, ierr)

go to 90

! цикл для приема следующей строки матрицы

endif

200 continue

Каждый подчиненный процесс получает вектор b. Затем организуется цикл, состоящий в том, что подчиненный процесс получает очередную строку матрицы А, формирует скалярное произведение строки и вектора b, посылает результат главному процессу, получает новую строку и так далее.