MPI_OP_创建函数

MPI_OP_创建函数,mpi,Mpi,我想要写函数,它将比较所有进程的数字并返回最小值(数字必须是正数) void findindexforminorm(double*invec,double*inoutvec,int*,MPI\u数据类型*){ 如果(invec[0]>0){ if(inoutvec[0]>invec[0]| | inoutvec[0]0){ MPI_Recv(tempbuf,count,datatype,rank-1,…); 用户减少(tempbuf、sendbuf、count、数据类型); } 如果(排名

我想要写函数,它将比较所有进程的数字并返回最小值(数字必须是正数)

void findindexforminorm(double*invec,double*inoutvec,int*,MPI\u数据类型*){
如果(invec[0]>0){
if(inoutvec[0]>invec[0]| | inoutvec[0]<0){
inoutvec[0]=invec[0];
/*inoutvec[1]=invec[1]*/
}
}
}

inoutvec是否适用于所有进程?

inoutvec
并非适用于所有进程

您的操作只需计算
inoutvec=min(invec,inoutvec)
,MPI库将负责通信并使用适当的
inoutvec
调用操作员

MPI标准第5.9.5章第185页:

对实施者的建议。我们在下面概述一个幼稚而低效的例子 MPI_REDUCE的实现不支持
就地
选项

MPI_Comm_size(comm, &groupsize);
MPI_Comm_rank(comm, &rank);
if (rank > 0) {
MPI_Recv(tempbuf, count, datatype, rank-1,...);
User_reduce(tempbuf, sendbuf, count, datatype);
}
if (rank < groupsize-1) {
MPI_Send(sendbuf, count, datatype, rank+1, ...);
}
/* answer now resides in process groupsize-1 ... now send to root
*/
if (rank == root) {
MPI_Irecv(recvbuf, count, datatype, groupsize-1,..., &req);
}
if (rank == groupsize-1) {
MPI_Send(sendbuf, count, datatype, root, ...);
}
if (rank == root) {
MPI_Wait(&req, &status);
}
MPI\u Comm\u大小(Comm和groupsize);
MPI_通信等级(通信和等级);
如果(排名>0){
MPI_Recv(tempbuf,count,datatype,rank-1,…);
用户减少(tempbuf、sendbuf、count、数据类型);
}
如果(排名

我认为用一些代码来说明是最容易的。正如Gilles所解释的,MPI将负责所有的通信并跨流程进行缩减——您只需要指定成对比较函数。请注意,缩减操作的原型由MPI固定,并允许向量缩减:第三个参数是每个进程上向量长度的计数(而不是隐式表示通信器大小的进程数)。除了void与双指针的一些小问题外,您的比较函数可以按原样注册并用于简化操作:

#include <stdio.h>
#include <mpi.h>

void findminnorm(void *invec, void *inoutvec, int *len, MPI_Datatype *datatype)
{
  int i;

  double *invecdble    = (double *) invec;
  double *inoutvecdble = (double *) inoutvec;

  for (i=0; i < *len; i++)
    {
      if (invecdble[i] > 0)
      {
        if (inoutvecdble[i] > invecdble[i] || inoutvecdble[i] < 0)
          {
            inoutvecdble[i] = invecdble[i];
          }
       }
    }
}


#define N 2

int main()
{
  int i;
  double input[N], output[N];

  int rank, size;
  MPI_Op MPI_MINNORM;

  MPI_Init(NULL,NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);

  MPI_Op_create(findminnorm, 1, &MPI_MINNORM);

  for (i=0; i < N; i++)
    {
      input[i] = (-size/2+rank+i)*(i+1);
      printf("On rank %d,  input[%d] = %f\n", rank, i, input[i]);
      output[i] = -1;
    }

  MPI_Allreduce(&input, &output, N, MPI_DOUBLE, MPI_MINNORM, MPI_COMM_WORLD);

  for (i=0; i < N; i++)
    {
      printf("On rank %d, output[%d] = %f\n", rank, i, output[i]);
    }

  MPI_Finalize();
}

我认为简单的答案是否定的。您需要使用一种MPI方法在不同的进程之间共享数据。但是,如何实现标准的最小值函数呢?
#include <stdio.h>
#include <mpi.h>

void findminnorm(void *invec, void *inoutvec, int *len, MPI_Datatype *datatype)
{
  int i;

  double *invecdble    = (double *) invec;
  double *inoutvecdble = (double *) inoutvec;

  for (i=0; i < *len; i++)
    {
      if (invecdble[i] > 0)
      {
        if (inoutvecdble[i] > invecdble[i] || inoutvecdble[i] < 0)
          {
            inoutvecdble[i] = invecdble[i];
          }
       }
    }
}


#define N 2

int main()
{
  int i;
  double input[N], output[N];

  int rank, size;
  MPI_Op MPI_MINNORM;

  MPI_Init(NULL,NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);

  MPI_Op_create(findminnorm, 1, &MPI_MINNORM);

  for (i=0; i < N; i++)
    {
      input[i] = (-size/2+rank+i)*(i+1);
      printf("On rank %d,  input[%d] = %f\n", rank, i, input[i]);
      output[i] = -1;
    }

  MPI_Allreduce(&input, &output, N, MPI_DOUBLE, MPI_MINNORM, MPI_COMM_WORLD);

  for (i=0; i < N; i++)
    {
      printf("On rank %d, output[%d] = %f\n", rank, i, output[i]);
    }

  MPI_Finalize();
}
mpirun -n 5 ./minnorm | grep input | sort
On rank 0,  input[0] = -2.000000
On rank 0,  input[1] = -2.000000
On rank 1,  input[0] = -1.000000
On rank 1,  input[1] = 0.000000
On rank 2,  input[0] = 0.000000
On rank 2,  input[1] = 2.000000
On rank 3,  input[0] = 1.000000
On rank 3,  input[1] = 4.000000
On rank 4,  input[0] = 2.000000
On rank 4,  input[1] = 6.000000

mpirun -n 5 ./minnorm | grep output | sort
On rank 0, output[0] = 1.000000
On rank 0, output[1] = 2.000000
On rank 1, output[0] = 1.000000
On rank 1, output[1] = 2.000000
On rank 2, output[0] = 1.000000
On rank 2, output[1] = 2.000000
On rank 3, output[0] = 1.000000
On rank 3, output[1] = 2.000000
On rank 4, output[0] = 1.000000
On rank 4, output[1] = 2.000000