/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1997 The Ohio State University
 *	RBD/JRV/NJN
 *
 *	$Id: lamreduce.c,v 6.5 1999/08/14 22:06:55 jsquyres Exp $
 *
 *	Function:	- all predefined reduce operations
 *			- min, max, sum, product
 *			- and, or, xor (bitwise and logical)
 *			- minloc, maxloc, replace
 */

#include <string.h>

#include <blktype.h>
#include <mpi.h>
#include <mpisys.h>
#include <typical.h>

/*
 * local structures
 */
struct dblcplex { double r; double i; };
struct complex { float r; float i; };
struct fltflt { float v; float k; };
struct fltint { float v; int k; };
struct dbldbl { double v; double k; };
struct dblint { double v; int k; };
struct intint { int v; int k; };
struct longint { long v; int k; };
struct shortint { short v; int k; };
#if LAM_SIZEOF_LONG_DOUBLE
struct ldblint { long double v; int k; };
#else
struct ldblint { double v; int k; };
#endif

void
lam_max(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	float		*pfin, *pfout;
	double		*pdin, *pdout;
#if LAM_SIZEOF_LONG_DOUBLE
	long double	*pldin, *pldout;
#else
	double		*pldin, *pldout;
#endif
#if LAM_SIZEOF_LONG_LONG
	long long	*pllin, *pllout;
	unsigned long long
			*pullin, *pullout;
#else
	long		*pllin, *pllout;
	unsigned long 	*pullin, *pullout;
#endif
	
	if (*datatype == MPI_INT || *datatype == MPI_F_INTEGER) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			if (*piin > *piout) {
				*piout = *piin;
			}
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			if (*plin > *plout) {
				*plout = *plin;
			}
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			if (*psin > *psout) {
				*psout = *psin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			if (*pusin > *pusout) {
				*pusout = *pusin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			if (*puin > *puout) {
				*puout = *puin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			if (*pulin > *pulout) {
				*pulout = *pulin;
			}
		}
		return;
	}

	if (*datatype == MPI_FLOAT || *datatype == MPI_F_REAL) {
		pfin = (float *) invec;
		pfout = (float *) inoutvec;
		for (i = 0; i < *len; ++i, ++pfin, ++pfout) {
			if (*pfin > *pfout) {
				*pfout = *pfin;
			}
		}
		return;
	}

	if (*datatype == MPI_DOUBLE || *datatype == MPI_F_DOUBLE_PRECISION) {
		pdin = (double *) invec;
		pdout = (double *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdin, ++pdout) {
			if (*pdin > *pdout) {
				*pdout = *pdin;
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_DOUBLE) {
#if LAM_SIZEOF_LONG_DOUBLE
		pldin = (long double *) invec;
		pldout = (long double *) inoutvec;
#else
		pldin = (double *) invec;
		pldout = (double *) inoutvec;
#endif
		for (i = 0; i < *len; ++i, ++pldin, ++pldout) {
			if (*pldin > *pldout) {
				*pldout = *pldin;
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_LONG_INT) {
#if LAM_SIZEOF_LONG_LONG
		pllin = (long long *) invec;
		pllout = (long long *) inoutvec;
#else
		pllin = (long *) invec;
		pllout = (long *) inoutvec;
#endif
		for (i = 0; i < *len; ++i, ++pllin, ++pllout) {
			if (*pllin > *pllout) {
				*pllout = *pllin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG_LONG) {
#if LAM_SIZEOF_LONG_LONG
		pullin = (unsigned long long *) invec;
		pullout = (unsigned long long *) inoutvec;
#else
		pullin = (unsigned long *) invec;
		pullout = (unsigned long *) inoutvec;
#endif
		for (i = 0; i < *len; ++i, ++pullin, ++pullout) {
			if (*pullin > *pullout) {
				*pullout = *pullin;
			}
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_min(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	float		*pfin, *pfout;
	double		*pdin, *pdout;
#if LAM_SIZEOF_LONG_DOUBLE
	long double	*pldin, *pldout;
#else
	double		*pldin, *pldout;
#endif

	if (*datatype == MPI_INT || *datatype == MPI_F_INTEGER) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			if (*piin < *piout) {
				*piout = *piin;
			}
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			if (*plin < *plout) {
				*plout = *plin;
			}
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			if (*psin < *psout) {
				*psout = *psin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			if (*pusin < *pusout) {
				*pusout = *pusin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			if (*puin < *puout) {
				*puout = *puin;
			}
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			if (*pulin < *pulout) {
				*pulout = *pulin;
			}
		}
		return;
	}

	if (*datatype == MPI_FLOAT || *datatype == MPI_F_REAL) {
		pfin = (float *) invec;
		pfout = (float *) inoutvec;
		for (i = 0; i < *len; ++i, ++pfin, ++pfout) {
			if (*pfin < *pfout) {
				*pfout = *pfin;
			}
		}
		return;
	}

	if (*datatype == MPI_DOUBLE || *datatype == MPI_F_DOUBLE_PRECISION) {
		pdin = (double *) invec;
		pdout = (double *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdin, ++pdout) {
			if (*pdin < *pdout) {
				*pdout = *pdin;
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_DOUBLE) {
#if LAM_SIZEOF_LONG_DOUBLE
		pldin = (long double *) invec;
		pldout = (long double *) inoutvec;
#else
		pldin = (double *) invec;
		pldout = (double *) inoutvec;
#endif
		for (i = 0; i < *len; ++i, ++pldin, ++pldout) {
			if (*pldin < *pldout) {
				*pldout = *pldin;
			}
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_sum(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	float		*pfin, *pfout;
	double		*pdin, *pdout;
	struct complex	*pxin, *pxout;
	struct dblcplex	*pdxin, *pdxout;
#if LAM_SIZEOF_LONG_DOUBLE
	long double	*pldin, *pldout;
#else
	double		*pldin, *pldout;
#endif

	if (*datatype == MPI_INT || *datatype == MPI_F_INTEGER) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout += *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout += *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout += *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout += *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout += *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout += *pulin;
		}
		return;
	}

	if (*datatype == MPI_FLOAT  || *datatype == MPI_F_REAL) {
		pfin = (float *) invec;
		pfout = (float *) inoutvec;
		for (i = 0; i < *len; ++i, ++pfin, ++pfout) {
			*pfout += *pfin;
		}
		return;
	}

	if (*datatype == MPI_F_COMPLEX) {
		pxin = (struct complex *) invec;
		pxout = (struct complex *) inoutvec;
		for (i = 0; i < *len; ++i, ++pxin, ++pxout) {
			pxout->r += pxin->r;
			pxout->i += pxin->i;
		}
		return;
	}

	if (*datatype == MPI_F_DOUBLE_COMPLEX) {
		pdxin = (struct dblcplex *) invec;
		pdxout = (struct dblcplex *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdxin, ++pdxout) {
			pdxout->r += pdxin->r;
			pdxout->i += pdxin->i;
		}
		return;
	}

	if (*datatype == MPI_DOUBLE || *datatype == MPI_F_DOUBLE_PRECISION) {
		pdin = (double *) invec;
		pdout = (double *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdin, ++pdout) {
			*pdout += *pdin;
		}
		return;
	}

	if (*datatype == MPI_LONG_DOUBLE) {
#if LAM_SIZEOF_LONG_DOUBLE
		pldin = (long double *) invec;
		pldout = (long double *) inoutvec;
#else
		pldin = (double *) invec;
		pldout = (double *) inoutvec;
#endif
		for (i = 0; i < *len; ++i, ++pldin, ++pldout) {
			*pldout += *pldin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_prod(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	float		*pfin, *pfout;
	float		xr, xi;
	double		dxr, dxi;
	double		*pdin, *pdout;
	struct complex	*pxin, *pxout;
	struct dblcplex	*pdxin, *pdxout;
#if LAM_SIZEOF_LONG_DOUBLE
	long double	*pldin, *pldout;
#else
	double		*pldin, *pldout;
#endif

	if (*datatype == MPI_INT || *datatype == MPI_F_INTEGER) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout *= *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout *= *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout *= *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout *= *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout *= *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout *= *pulin;
		}
		return;
	}

	if (*datatype == MPI_FLOAT || *datatype == MPI_F_REAL) {
		pfin = (float *) invec;
		pfout = (float *) inoutvec;
		for (i = 0; i < *len; ++i, ++pfin, ++pfout) {
			*pfout *= *pfin;
		}
		return;
	}

	if (*datatype == MPI_F_COMPLEX) {
		pxin = (struct complex *) invec;
		pxout = (struct complex *) inoutvec;
		for (i = 0; i < *len; ++i, ++pxin, ++pxout) {
			xr = pxout->r;
			xi = pxout->i;
			pxout->r = (xr * pxin->r) - (xi * pxin->i);
			pxout->i = (xr * pxin->i) + (xi * pxin->r);
		}
		return;
	}

	if (*datatype == MPI_F_DOUBLE_COMPLEX) {
		pdxin = (struct dblcplex *) invec;
		pdxout = (struct dblcplex *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdxin, ++pdxout) {
			dxr = pdxout->r;
			dxi = pdxout->i;
			pdxout->r = (dxr * pdxin->r) - (dxi * pdxin->i);
			pdxout->i = (dxr * pdxin->i) + (dxi * pdxin->r);
		}
		return;
	}

	if (*datatype == MPI_DOUBLE || *datatype == MPI_F_DOUBLE_PRECISION) {
		pdin = (double *) invec;
		pdout = (double *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdin, ++pdout) {
			*pdout *= *pdin;
		}
		return;
	}

	if (*datatype == MPI_LONG_DOUBLE) {
#if LAM_SIZEOF_LONG_DOUBLE
		pldin = (long double *) invec;
		pldout = (long double *) inoutvec;
#else
		pldin = (double *) invec;
		pldout = (double *) inoutvec;
#endif
		for (i = 0; i < *len; ++i, ++pldin, ++pldout) {
			*pldout *= *pldin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_land(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;

	if ((*datatype == MPI_INT) || (*datatype == MPI_F_LOGICAL)
			|| (*datatype == MPI_F_INTEGER)) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout = *piout && *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout = *plout && *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout = *psout && *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout = *pusout && *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout = *puout && *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout = *pulout && *pulin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_lor(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;

	if ((*datatype == MPI_INT) || (*datatype == MPI_F_LOGICAL)
			|| (*datatype == MPI_F_INTEGER)) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout = *piout || *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout = *plout || *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout = *psout || *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout = *pusout || *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout = *puout || *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout = *pulout || *pulin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_lxor(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;

	if ((*datatype == MPI_INT) || (*datatype == MPI_F_LOGICAL)
			|| (*datatype == MPI_F_INTEGER)) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout = (*piout || *piin) && !(*piout && *piin);
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout = (*plout || *plin) && !(*plout && *plin);
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout = (*psout || *psin) && !(*psout && *psin);
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout = (*pusout || *pusin) && !(*pusout && *pusin);
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout = (*puout || *puin) && !(*puout && *puin);
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout = (*pulout || *pulin) && !(*pulout && *pulin);
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_band(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	unsigned char	*pucin, *pucout;

	if ((*datatype == MPI_INT) || (*datatype == MPI_F_LOGICAL)
			|| (*datatype == MPI_F_INTEGER)) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout &= *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout &= *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout &= *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout &= *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout &= *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout &= *pulin;
		}
		return;
	}

	if (*datatype == MPI_BYTE) {
		pucin = (unsigned char *) invec;
		pucout = (unsigned char *) inoutvec;
		for (i = 0; i < *len; ++i, ++pucin, ++pucout) {
			*pucout &= *pucin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_bor(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	unsigned char	*pucin, *pucout;

	if ((*datatype == MPI_INT) || (*datatype == MPI_F_LOGICAL)
			|| (*datatype == MPI_F_INTEGER)) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout |= *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout |= *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout |= *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout |= *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout |= *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout |= *pulin;
		}
		return;
	}

	if (*datatype == MPI_BYTE) {
		pucin = (unsigned char *) invec;
		pucout = (unsigned char *) inoutvec;
		for (i = 0; i < *len; ++i, ++pucin, ++pucout) {
			*pucout |= *pucin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_bxor(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	int		*piin, *piout;
	long		*plin, *plout;
	short		*psin, *psout;
	unsigned short	*pusin, *pusout;
	unsigned	*puin, *puout;
	unsigned long	*pulin, *pulout;
	unsigned char	*pucin, *pucout;

	if ((*datatype == MPI_INT) || (*datatype == MPI_F_LOGICAL)
			|| (*datatype == MPI_F_INTEGER)) {
		piin = (int *) invec;
		piout = (int *) inoutvec;
		for (i = 0; i < *len; ++i, ++piin, ++piout) {
			*piout ^= *piin;
		}
		return;
	}

	if (*datatype == MPI_LONG) {
		plin = (long *) invec;
		plout = (long *) inoutvec;
		for (i = 0; i < *len; ++i, ++plin, ++plout) {
			*plout ^= *plin;
		}
		return;
	}

	if (*datatype == MPI_SHORT) {
		psin = (short *) invec;
		psout = (short *) inoutvec;
		for (i = 0; i < *len; ++i, ++psin, ++psout) {
			*psout ^= *psin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_SHORT) {
		pusin = (unsigned short *) invec;
		pusout = (unsigned short *) inoutvec;
		for (i = 0; i < *len; ++i, ++pusin, ++pusout) {
			*pusout ^= *pusin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED) {
		puin = (unsigned *) invec;
		puout = (unsigned *) inoutvec;
		for (i = 0; i < *len; ++i, ++puin, ++puout) {
			*puout ^= *puin;
		}
		return;
	}

	if (*datatype == MPI_UNSIGNED_LONG) {
		pulin = (unsigned long *) invec;
		pulout = (unsigned long *) inoutvec;
		for (i = 0; i < *len; ++i, ++pulin, ++pulout) {
			*pulout ^= *pulin;
		}
		return;
	}

	if (*datatype == MPI_BYTE) {
		pucin = (unsigned char *) invec;
		pucout = (unsigned char *) inoutvec;
		for (i = 0; i < *len; ++i, ++pucin, ++pucout) {
			*pucout ^= *pucin;
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_maxloc(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	struct fltflt	*pffin, *pffout;
	struct fltint	*pfiin, *pfiout;
	struct dbldbl	*pddin, *pddout;
	struct dblint	*pdiin, *pdiout;
	struct ldblint	*pldiin, *pldiout;
	struct intint	*piiin, *piiout;
	struct longint	*pliin, *pliout;
	struct shortint	*psiin, *psiout;

	if (*datatype == MPI_F_2REAL) {
		pffin = (struct fltflt *) invec;
		pffout = (struct fltflt *) inoutvec;
		for (i = 0; i < *len; ++i, ++pffin, ++pffout) {
			if (pffin->v > pffout->v) {
				pffout->v = pffin->v;
				pffout->k = pffin->k;
			}
			else if (pffin->v == pffout->v) {
				pffout->k = LAM_min(pffin->k, pffout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_FLOAT_INT) {
		pfiin = (struct fltint *) invec;
		pfiout = (struct fltint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pfiin, ++pfiout) {
			if (pfiin->v > pfiout->v) {
				pfiout->v = pfiin->v;
				pfiout->k = pfiin->k;
			}
			else if (pfiin->v == pfiout->v) {
				pfiout->k = LAM_min(pfiin->k, pfiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_F_2DOUBLE_PRECISION) {
		pddin = (struct dbldbl *) invec;
		pddout = (struct dbldbl *) inoutvec;
		for (i = 0; i < *len; ++i, ++pddin, ++pddout) {
			if (pddin->v > pddout->v) {
				pddout->v = pddin->v;
				pddout->k = pddin->k;
			}
			else if (pddin->v == pddout->v) {
				pddout->k = LAM_min(pddin->k, pddout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_DOUBLE_INT) {
		pdiin = (struct dblint *) invec;
		pdiout = (struct dblint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdiin, ++pdiout) {
			if (pdiin->v > pdiout->v) {
				pdiout->v = pdiin->v;
				pdiout->k = pdiin->k;
			}
			else if (pdiin->v == pdiout->v) {
				pdiout->k = LAM_min(pdiin->k, pdiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_DOUBLE_INT) {
		pldiin = (struct ldblint *) invec;
		pldiout = (struct ldblint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pldiin, ++pldiout) {
			if (pldiin->v > pldiout->v) {
				pldiout->v = pldiin->v;
				pldiout->k = pldiin->k;
			}
			else if (pldiin->v == pldiout->v) {
				pldiout->k = LAM_min(pldiin->k, pldiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_2INT || *datatype == MPI_F_2INTEGER) {
		piiin = (struct intint *) invec;
		piiout = (struct intint *) inoutvec;
		for (i = 0; i < *len; ++i, ++piiin, ++piiout) {
			if (piiin->v > piiout->v) {
				piiout->v = piiin->v;
				piiout->k = piiin->k;
			}
			else if (piiin->v == piiout->v) {
				piiout->k = LAM_min(piiin->k, piiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_INT) {
		pliin = (struct longint *) invec;
		pliout = (struct longint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pliin, ++pliout) {
			if (pliin->v > pliout->v) {
				pliout->v = pliin->v;
				pliout->k = pliin->k;
			}
			else if (pliin->v == pliout->v) {
				pliout->k = LAM_min(pliin->k, pliout->k);
			}
		}
		return;
	}
	
	if (*datatype == MPI_SHORT_INT) {
		psiin = (struct shortint *) invec;
		psiout = (struct shortint *) inoutvec;
		for (i = 0; i < *len; ++i, ++psiin, ++psiout) {
			if (psiin->v > psiout->v) {
				psiout->v = psiin->v;
				psiout->k = psiin->k;
			}
			else if (psiin->v == psiout->v) {
				psiout->k = LAM_min(psiin->k, psiout->k);
			}
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}


void
lam_minloc(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	int		i;
	struct fltflt	*pffin, *pffout;
	struct fltint	*pfiin, *pfiout;
	struct dbldbl	*pddin, *pddout;
	struct dblint	*pdiin, *pdiout;
	struct ldblint	*pldiin, *pldiout;
	struct intint	*piiin, *piiout;
	struct longint	*pliin, *pliout;
	struct shortint	*psiin, *psiout;

	if (*datatype == MPI_F_2REAL) {
		pffin = (struct fltflt *) invec;
		pffout = (struct fltflt *) inoutvec;
		for (i = 0; i < *len; ++i, ++pffin, ++pffout) {
			if (pffin->v < pffout->v) {
				pffout->v = pffin->v;
				pffout->k = pffin->k;
			}
			else if (pffin->v == pffout->v) {
				pffout->k = LAM_min(pffin->k, pffout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_FLOAT_INT) {
		pfiin = (struct fltint *) invec;
		pfiout = (struct fltint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pfiin, ++pfiout) {
			if (pfiin->v < pfiout->v) {
				pfiout->v = pfiin->v;
				pfiout->k = pfiin->k;
			}
			else if (pfiin->v == pfiout->v) {
				pfiout->k = LAM_min(pfiin->k, pfiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_F_2DOUBLE_PRECISION) {
		pddin = (struct dbldbl *) invec;
		pddout = (struct dbldbl *) inoutvec;
		for (i = 0; i < *len; ++i, ++pddin, ++pddout) {
			if (pddin->v < pddout->v) {
				pddout->v = pddin->v;
				pddout->k = pddin->k;
			}
			else if (pddin->v == pddout->v) {
				pddout->k = LAM_min(pddin->k, pddout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_DOUBLE_INT) {
		pdiin = (struct dblint *) invec;
		pdiout = (struct dblint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pdiin, ++pdiout) {
			if (pdiin->v < pdiout->v) {
				pdiout->v = pdiin->v;
				pdiout->k = pdiin->k;
			}
			else if (pdiin->v == pdiout->v) {
				pdiout->k = LAM_min(pdiin->k, pdiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_DOUBLE_INT) {
		pldiin = (struct ldblint *) invec;
		pldiout = (struct ldblint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pldiin, ++pldiout) {
			if (pldiin->v < pldiout->v) {
				pldiout->v = pldiin->v;
				pldiout->k = pldiin->k;
			}
			else if (pldiin->v == pldiout->v) {
				pldiout->k = LAM_min(pldiin->k, pldiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_2INT || *datatype == MPI_F_2INTEGER) {
		piiin = (struct intint *) invec;
		piiout = (struct intint *) inoutvec;
		for (i = 0; i < *len; ++i, ++piiin, ++piiout) {
			if (piiin->v < piiout->v) {
				piiout->v = piiin->v;
				piiout->k = piiin->k;
			}
			else if (piiin->v == piiout->v) {
				piiout->k = LAM_min(piiin->k, piiout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_LONG_INT) {
		pliin = (struct longint *) invec;
		pliout = (struct longint *) inoutvec;
		for (i = 0; i < *len; ++i, ++pliin, ++pliout) {
			if (pliin->v < pliout->v) {
				pliout->v = pliin->v;
				pliout->k = pliin->k;
			}
			else if (pliin->v == pliout->v) {
				pliout->k = LAM_min(pliin->k, pliout->k);
			}
		}
		return;
	}

	if (*datatype == MPI_SHORT_INT) {
		psiin = (struct shortint *) invec;
		psiout = (struct shortint *) inoutvec;
		for (i = 0; i < *len; ++i, ++psiin, ++psiout) {
			if (psiin->v < psiout->v) {
				psiout->v = psiin->v;
				psiout->k = psiin->k;
			}
			else if (psiin->v == psiout->v) {
				psiout->k = LAM_min(psiin->k, psiout->k);
			}
		}
		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}

void
lam_replace(invec, inoutvec, len, datatype)

void			*invec;
void			*inoutvec;
int			*len;
MPI_Datatype		*datatype;

{
	if (*datatype == MPI_INT
		|| *datatype == MPI_F_INTEGER
		|| *datatype == MPI_LONG
		|| *datatype == MPI_SHORT
		|| *datatype == MPI_UNSIGNED_SHORT
		|| *datatype == MPI_UNSIGNED
		|| *datatype == MPI_UNSIGNED_LONG
		|| *datatype == MPI_FLOAT
		|| *datatype == MPI_F_REAL
		|| *datatype == MPI_DOUBLE
		|| *datatype == MPI_F_DOUBLE_PRECISION
		|| *datatype == MPI_LONG_DOUBLE
		|| *datatype == MPI_LONG_LONG_INT
		|| *datatype == MPI_UNSIGNED_LONG_LONG) {

		memcpy((char *) inoutvec,
			(char *) invec, *len * (*datatype)->dt_size);

		return;
	}

	(void) lam_errfunc(MPI_COMM_WORLD,
				lam_getfunc(), lam_mkerr(MPI_ERR_OP, 0));
}
