Оператор MPI_MINLOC используется для расчета глобального минимума и соответствующего ему индекса. MPI_MAXLOC аналогично считает глобальный максимум и индекс. Одно из применений этих операций - вычисление глобального минимума (максимума) и номера процесса, содержащего это значение.
Операция, которая определяет MPI_MAXLOC , такова:
где w = max(u, v) и
MPI_MINLOC определен аналогично:
где w = min(u, v) и
Обе операции ассоциативны и коммутативны. Отметим, что если MPI_MAXLOC применяется для последовательности пар (u, 0), (u, 1), ..., (u, n-1), то возвращаемое значение есть (u, r), где u=max(u и r - индекс первого глобального максимума в последовательности. Таким образом, если каждый процесс предоставляет значение и свой номер в группе, тогда операция редукции с op = MPI_MAXLOC возвратит значение максимума и номер первого процесса с этим значением. Аналогично, MPI_MINLOC может быть использована для получения минимума и его индекса. В общем, MPI_MINLOC вычисляет лексикографический минимум , где элементы упорядочены согласно первому компоненту каждой пары, и отношение разрешается согласно второму компоненту.
Операция редукции определена для работы с аргументами, содержащими пару: значение и индекс. Как в языке ФОРТРАН , так и для языка Си имеются типы данных для описания этой пары. Потенциально смешанная природа таких параметров является проблемой для языка ФОРТРАН. Для языка ФОРТРАН проблема обойдена благодаря наличию в MPI типа, состоящего из пары того же типа, что и значение, и присоединенного к этому типу индекса. Для языка Си MPI предоставляет парный тип, части которого имеют различный тип и индекс имеет тип int .
Чтобы использовать MPI_MINLOC и MPI_MAXLOC в операции редукции, нужно обеспечить аргумент datatype, который представляет пару (значение и индекс). MPI предоставляет девять таких предопределенных типов данных. Операции MPI_MAXLOC и MPI_MINLOC могут быть использованы со следующими типами данных:
ФОРТРАН: | |
Название | Описание |
MPI_2REAL | пара переменных типа REAL |
MPI_2DOUBLE_PRECISION | пара переменных типа DOUBLE PRECISION |
MPI_2INTEGER | пара переменных типа INTEGER |
Си: | |
Название | Описание |
MPI_FLOAT_INT | переменные типа float и int |
MPI_DOUBLE_INT | переменные типа double и int |
MPI_LONG_INT | переменные типа long и int |
MPI_2INT | пара переменных типа int |
MPI_SHORT_INT | переменные типа short и int |
MPI_LONG_DOUBLE_INT | переменные типа long double и int |
Тип данных MPI_2REAL аналогичен тому, как если бы он был определен следующим образом (см. раздел 3.12).
MPI_TYPE_CONTIGOUS(2, MPI_REAL, MPI_2REAL)
Аналогичными выражениями задаются MPI_2INTEGER, MPI_2DOUBLE_PRECISION и MPI_2INT.
Тип данных MPI_FLOAT_INT аналогичен тому, как если бы он был объявлен следующей последовательностью инструкций.
type[0] = MPI_FLOAT
type[1] = MPI_INT
disp[0] = 0
disp[1] = sizeof(float)
block[0] = 1
block[1] = 1
MPI_TYPE_STRUCT(2, block, disp, type, MPI_FLOAT_INT)
Подобные выражения относятся и к MPI_LONG_INT и MPI_DOUBLE_INT.
Пример 4.17 Каждый процесс имеет массив 30 чисел типа double на языке Си. Для каждой из 30 областей надо вычислить значение и номер процесса, содержащего наибольшее значение.
...
/* каждый процесс имет массив из 30 чисел двойной точности: ain[30]
*/
double ain[30], aout[30];
int ind[30];
struct {
double val;
int rank;
} in[30], out[30];
int i, myrank, root;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
for (i=0; i<30; ++i) {
in[i].val = ain[i];
in[i].rank = myrank;
}
MPI_Reduce(in, out, 30, MPI_DOUBLE_INT, MPI_MAXLOC, root, comm);
/* в этой точке результат помещается на корневой процесс
*/
if (myrank == root) {
/* читаются выходные номера
*/
for (i=0; i<30; ++i) {
aout[i] = out[i].val;
ind[i] = out[i].rank; !номер обратно преобразуется в целое
}
}
Пример 4.18 Тот же пример для языка ФОРТРАН.
...
! каждый процесс имеет массив из 30 чисел двойной точности: ain(30)
DOUBLE PRECISION ain(30), aout(30)
INTEGER ind(30);
DOUBLE PRECISION in(2,30), out(2,30)
INTEGER i, myrank, root, ierr;
MPI_COMM_RANK(MPI_COMM_WORLD, myrank);
DO I=1, 30
in(1,i) = ain(i)
in(2,i) = myrank ! myrank преобразуется к типу double
END DO
MPI_REDUCE(in, out, 30, MPI_2DOUBLE_PRECISION, MPI_MAXLOC, root,
comm, ierr);
! в этой точке результат помещается на корневой процесс
IF (myrank .EQ. root) THEN
! читаются выходные номера
DO I= 1, 30
aout(i) = out(1,i)
ind(i) = out(2,i)
END DO
END IF
Пример 4.19 Каждый процесс имеет непустой массив чисел. Требуется найти минимальное глобальное число, номер процесса, хранящего его, и его индекс в этом процессе.
#define LEN 1000
float val[LEN]; /* локальный массив значений */
int count; /* локальное количество значений */
int myrank, minrank, minindex;
float minval;
struct {
float value;
int index;
} in, out;
/* локальный minloc */
in.value = val[0];
in.index = 0;
for (i=1; i < count; i++)
if (in.value > val[i]) {
in.value = val[i];
in.index = i;
}
/* глобальный minloc */
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
in.index = myrank*LEN + in.index;
MPI_Reduce(in, out, 1, MPI_FLOAT_INT, MPI_MINLOC, root, comm);
/* в этой точке результат помещается на корневой процесс
*/
if (myrank == root) {
minval = out.value;
minrank = out.index / LEN;
minindex = out.index % LEN;
}
Объяснение: Данное здесь определение MPI_MINLOC и MPI_MAXLOC имеет то достоинство, что оно не приводит к необходимости какой-либо специальной обработки для этих двух операций: они обрабатываются, как и другие операции редукции. Если необходимо, программист может создать собственные определения MPI_MAXLOC и MPI_MINLOC . Недостаток определения состоит в том, что значения и индексы должны чередоваться, и индексы и переменные должны быть приведены к одному типу для языка ФОРТРАН.[]