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

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