Пример 4.22 Этот пример построен на пользовательской операции, чтобы выполнить сегментированный просмотр. При сегментированном просмотре на вход принимается множество значений и множество логических величин, логические значения устанавливают различные сегменты для просмотра. Например:
Оператор, производящий этот эффект
где
Отметим, что это некоммутативный оператор. Код на языке Си, реализующий вычисления, представлен ниже.
typedef struct {
double val;
int log;
} SegScanPair;
/* функция, определенная пользователем
*/
void segScan(SegScanPair *in, SegScanPair *inout,
int *len, MPI_Datatype *dptr)
{
int i;
SegScanPair c;
for (i=0; i< *len; ++i) {
if (in->log == inout->log)
c.val = in->val + inout->val;
else
c.val = inout->val;
c.log = inout->log;
*inout = c;
in++; inout++;
}
}
Заметим, что параметр inout в определяемой пользователем функции соответствует правому операнду оператора. При использовании этого оператора необходимо быть внимательным, чтобы описать, что он некоммутативный, как в следующем листинге.
int i,base;
SeqScanPair a, answer;
MPI_Op myOp;
MPI_Datatype type[2] = {MPI_DOUBLE, MPI_INT};
MPI_Aint disp[2];
int blocklen[2] = { 1, 1};
MPI_Datatype sspair;
/* объяснение для MPI, как определяется тип SegScanPair
*/
MPI_Address(a, disp);
MPI_Address(a.log, disp+1);
base = disp[0];
for (i=0; i<2; ++i) disp[i] -= base;
MPI_Type_struct(2, blocklen, disp, type, &sspair);
MPI_Type_commit(&sspair);
/* создается пользовательская операция segmented-scan
*/
MPI_Op_create(segScan, False, &myOp);
...
MPI_Scan(a, answer, 1, sspair, myOp, root, comm);