Blame test/mpi/cxx/coll/uallredx.cxx

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2003 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#include "mpi.h"
Packit Service c5cf8c
#include "mpitestconf.h"
Packit Service c5cf8c
#ifdef HAVE_IOSTREAM
Packit Service c5cf8c
// Not all C++ compilers have iostream instead of iostream.h
Packit Service c5cf8c
#include <iostream>
Packit Service c5cf8c
#ifdef HAVE_NAMESPACE_STD
Packit Service c5cf8c
// Those that do often need the std namespace; otherwise, a bare "cout"
Packit Service c5cf8c
// is likely to fail to compile
Packit Service c5cf8c
using namespace std;
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#else
Packit Service c5cf8c
#include <iostream.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#include "mpitestcxx.h"
Packit Service c5cf8c
#include <assert.h>
Packit Service c5cf8c
Packit Service c5cf8c
static char MTEST_Descrip[] = "Test MPI_Allreduce with non-commutative user-defined operations";
Packit Service c5cf8c
Packit Service c5cf8c
/* We make the error count global so that we can easily control the output
Packit Service c5cf8c
   of error information (in particular, limiting it after the first 10
Packit Service c5cf8c
   errors */
Packit Service c5cf8c
int errs = 0;
Packit Service c5cf8c
Packit Service c5cf8c
/* This implements a simple matrix-matrix multiply.  This is an associative
Packit Service c5cf8c
   but not commutative operation.  The matrix size is set in matSize;
Packit Service c5cf8c
   the number of matrices is the count argument. The matrix is stored
Packit Service c5cf8c
   in C order, so that
Packit Service c5cf8c
     c(i,j) is cin[j+i*matSize]
Packit Service c5cf8c
 */
Packit Service c5cf8c
#define MAXCOL 256
Packit Service c5cf8c
static int matSize = 0;         /* Must be < MAXCOL */
Packit Service c5cf8c
static int max_offset = 0;
Packit Service c5cf8c
void uop(const void *cinPtr, void *coutPtr, int count, const MPI::Datatype & dtype)
Packit Service c5cf8c
{
Packit Service c5cf8c
    const int *cin = (const int *) cinPtr;
Packit Service c5cf8c
    int *cout = (int *) coutPtr;
Packit Service c5cf8c
    int i, j, k, nmat;
Packit Service c5cf8c
    int tempcol[MAXCOL];
Packit Service c5cf8c
    int offset1, offset2;
Packit Service c5cf8c
    int matsize2 = matSize * matSize;
Packit Service c5cf8c
Packit Service c5cf8c
    for (nmat = 0; nmat < count; nmat++) {
Packit Service c5cf8c
        for (j = 0; j < matSize; j++) {
Packit Service c5cf8c
            for (i = 0; i < matSize; i++) {
Packit Service c5cf8c
                tempcol[i] = 0;
Packit Service c5cf8c
                for (k = 0; k < matSize; k++) {
Packit Service c5cf8c
                    /* col[i] += cin(i,k) * cout(k,j) */
Packit Service c5cf8c
                    offset1 = k + i * matSize;
Packit Service c5cf8c
                    offset2 = j + k * matSize;
Packit Service c5cf8c
                    assert(offset1 < max_offset);
Packit Service c5cf8c
                    assert(offset2 < max_offset);
Packit Service c5cf8c
                    tempcol[i] += cin[offset1] * cout[offset2];
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            for (i = 0; i < matSize; i++) {
Packit Service c5cf8c
                offset1 = j + i * matSize;
Packit Service c5cf8c
                assert(offset1 < max_offset);
Packit Service c5cf8c
                cout[offset1] = tempcol[i];
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        cin += matsize2;
Packit Service c5cf8c
        cout += matsize2;
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Initialize the integer matrix as a permutation of rank with rank+1.
Packit Service c5cf8c
   If we call this matrix P_r, we know that product of P_0 P_1 ... P_{size-2}
Packit Service c5cf8c
   is the the matrix representing the permutation that shifts left by one.
Packit Service c5cf8c
   As the final matrix (in the size-1 position), we use the matrix that
Packit Service c5cf8c
   shifts RIGHT by one
Packit Service c5cf8c
*/
Packit Service c5cf8c
static void initMat(MPI::Intracomm comm, int mat[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j, size, rank;
Packit Service c5cf8c
    int offset;
Packit Service c5cf8c
Packit Service c5cf8c
    rank = comm.Get_rank();
Packit Service c5cf8c
    size = comm.Get_size();
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < size * size; i++) {
Packit Service c5cf8c
        assert(i < max_offset);
Packit Service c5cf8c
        mat[i] = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (rank < size - 1) {
Packit Service c5cf8c
        /* Create the permutation matrix that exchanges r with r+1 */
Packit Service c5cf8c
        for (i = 0; i < size; i++) {
Packit Service c5cf8c
            if (i == rank) {
Packit Service c5cf8c
                offset = ((i + 1) % size) + i * size;
Packit Service c5cf8c
                assert(offset < max_offset);
Packit Service c5cf8c
                mat[offset] = 1;
Packit Service c5cf8c
            } else if (i == ((rank + 1) % size)) {
Packit Service c5cf8c
                offset = ((i + size - 1) % size) + i * size;
Packit Service c5cf8c
                assert(offset < max_offset);
Packit Service c5cf8c
                mat[offset] = 1;
Packit Service c5cf8c
            } else {
Packit Service c5cf8c
                offset = i + i * size;
Packit Service c5cf8c
                assert(offset < max_offset);
Packit Service c5cf8c
                mat[offset] = 1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        /* Create the permutation matrix that shifts right by one */
Packit Service c5cf8c
        for (i = 0; i < size; i++) {
Packit Service c5cf8c
            for (j = 0; j < size; j++) {
Packit Service c5cf8c
                offset = j + i * size;  /* location of c(i,j) */
Packit Service c5cf8c
                mat[offset] = 0;
Packit Service c5cf8c
                if (((j - i + size) % size) == 1)
Packit Service c5cf8c
                    mat[offset] = 1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Compare a matrix with the identity matrix */
Packit Service c5cf8c
static int isIdentity(MPI::Intracomm comm, int mat[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j, size, rank, lerrs = 0;
Packit Service c5cf8c
    int offset;
Packit Service c5cf8c
Packit Service c5cf8c
    rank = comm.Get_rank();
Packit Service c5cf8c
    size = comm.Get_size();
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < size; i++) {
Packit Service c5cf8c
        for (j = 0; j < size; j++) {
Packit Service c5cf8c
            if (i == j) {
Packit Service c5cf8c
                offset = j + i * size;
Packit Service c5cf8c
                assert(offset < max_offset);
Packit Service c5cf8c
                if (mat[offset] != 1) {
Packit Service c5cf8c
                    lerrs++;
Packit Service c5cf8c
                    if (errs + lerrs < 10) {
Packit Service c5cf8c
                        cerr << "[" << rank << "] mat[" << i << "," << j << "] = " << mat[offset] <<
Packit Service c5cf8c
                            ", expected 1 for comm " << MTestGetIntracommName() << endl;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            } else {
Packit Service c5cf8c
                offset = j + i * size;
Packit Service c5cf8c
                assert(offset < max_offset);
Packit Service c5cf8c
                if (mat[offset] != 0) {
Packit Service c5cf8c
                    lerrs++;
Packit Service c5cf8c
                    if (errs + lerrs < 10) {
Packit Service c5cf8c
                        cerr << "[" << rank << "] mat[" << i << "," << j << "] = " << mat[offset] <<
Packit Service c5cf8c
                            ", expected 0 for comm " << MTestGetIntracommName() << endl;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return lerrs;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int main(int argc, char *argv[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    int size;
Packit Service c5cf8c
    int minsize = 2, count;
Packit Service c5cf8c
    MPI::Intracomm comm;
Packit Service c5cf8c
    int *buf, *bufout;
Packit Service c5cf8c
    MPI::Op op;
Packit Service c5cf8c
    MPI::Datatype mattype;
Packit Service c5cf8c
Packit Service c5cf8c
    MTest_Init();
Packit Service c5cf8c
Packit Service c5cf8c
    op.Init(uop, false);
Packit Service c5cf8c
Packit Service c5cf8c
    while (MTestGetIntracommGeneral(comm, minsize, 1)) {
Packit Service c5cf8c
        if ((MPI::Intracomm) comm == (MPI::Intracomm) MPI_COMM_NULL) {
Packit Service c5cf8c
            continue;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        size = comm.Get_size();
Packit Service c5cf8c
        matSize = size;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Only one matrix for now */
Packit Service c5cf8c
        count = 1;
Packit Service c5cf8c
Packit Service c5cf8c
        /* A single matrix, the size of the communicator */
Packit Service c5cf8c
        mattype = MPI::INT.Create_contiguous(size * size);
Packit Service c5cf8c
        mattype.Commit();
Packit Service c5cf8c
Packit Service c5cf8c
        max_offset = count * size * size;
Packit Service c5cf8c
        buf = new int[max_offset];
Packit Service c5cf8c
        if (!buf) {
Packit Service c5cf8c
            MPI::COMM_WORLD.Abort(1);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        bufout = new int[max_offset];
Packit Service c5cf8c
        if (!bufout) {
Packit Service c5cf8c
            MPI::COMM_WORLD.Abort(1);
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        initMat(comm, buf);
Packit Service c5cf8c
        comm.Allreduce(buf, bufout, count, mattype, op);
Packit Service c5cf8c
        errs += isIdentity(comm, bufout);
Packit Service c5cf8c
Packit Service c5cf8c
        /* Try the same test, but using MPI_IN_PLACE */
Packit Service c5cf8c
        initMat(comm, bufout);
Packit Service c5cf8c
        comm.Allreduce(MPI_IN_PLACE, bufout, count, mattype, op);
Packit Service c5cf8c
        errs += isIdentity(comm, bufout);
Packit Service c5cf8c
Packit Service c5cf8c
        delete[]buf;
Packit Service c5cf8c
        delete[]bufout;
Packit Service c5cf8c
Packit Service c5cf8c
        mattype.Free();
Packit Service c5cf8c
        MTestFreeComm(comm);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    op.Free();
Packit Service c5cf8c
Packit Service c5cf8c
    MTest_Finalize(errs);
Packit Service c5cf8c
    return 0;
Packit Service c5cf8c
}