【问题标题】:MPI Receive and Send for Eigen compressed sparse matrix特征压缩稀疏矩阵的 MPI 接收和发送
【发布时间】:2018-10-02 06:26:41
【问题描述】:

发送和接收使用 Eigen 库定义的稀疏矩阵的最佳(最快)方法是什么?

目前,我正在创建一个值、行和列向量(来自预定义的稀疏矩阵),仅使用非零元素并一一发送/接收这 3 个向量。这些向量是简单的 std::vector

if (0 == myrank) {
    Sz.insert(0,0) = 0.5;       Sz.insert(1,1) = -0.5;

    //------ preparing to send ----------
    shape[0] = Sz.rows();
    shape[1] = Sz.cols();
    int size=Sz.nonZeros();
    val.resize(size); inner.resize(size); outer.resize(size);
    cout << "val-size = "<< val.size() << endl;
    int counter=0;
    for (int k=0; k<Sz.outerSize(); ++k) {
        for (CrsMatrixType::InnerIterator it(Sz,k); it; ++it)  {
            val[counter]=it.value();
            inner[counter]=it.col();
            outer[counter]=it.row();
            counter++;
        }
    }
    assert(counter==size);
    MPI_Send(&shape[0],2,MPI_INT,1, 100, MPI_COMM_WORLD);
    MPI_Send(&size,1,MPI_INT,1, 101, MPI_COMM_WORLD);
    MPI_Send(&val[0],size,MPI_DOUBLE,1, 102, MPI_COMM_WORLD);
    MPI_Send(&inner[0],size,MPI_INT,1, 103, MPI_COMM_WORLD);
    MPI_Send(&outer[0],size,MPI_INT,1, 104, MPI_COMM_WORLD);


}

稍后,我使用

收到它们
if (1 == myrank) {

    //------ preparing to receive ----------
    shape.resize(2);
    int size;
    MPI_Recv(&shape[0],2,MPI_INT,0, 100, MPI_COMM_WORLD, &status);
    MPI_Recv(&size,1,MPI_INT,0, 101, MPI_COMM_WORLD, &status);

    val.resize(size); inner.resize(size); outer.resize(size);
    MPI_Recv(&val[0],size,MPI_DOUBLE,0, 102, MPI_COMM_WORLD, &status);
    MPI_Recv(&inner[0],size,MPI_INT,0, 103, MPI_COMM_WORLD, &status);
    MPI_Recv(&outer[0],size,MPI_INT,0, 104, MPI_COMM_WORLD, &status);


    Sz.resize(shape[0],shape[1]);
    Sz.reserve(size); // allocate room for nonzero elements only.
    for (int k=0; k<Sz.outerSize(); ++k) {
        Sz.coeffRef(inner[k],outer[k]) = val[k];
    }

    cout << "my RANK " << myrank << endl;
    cout << Sz << endl;
}

并将它们添加到秩为 1 的稀疏矩阵中。

有没有更好的方法来做到这一点?谢谢。

【问题讨论】:

  • 首先,你应该一次性发送shapesize。然后您可以创建一个struct,其中有两个MPI_INT 和一个MPI_ DOUBLE,描述矩阵的一个元素,分配和填充它,为此构建派生数据类型,然后一次性发送size 元素。
  • 谢谢! :D 我在下面附上@chtz 评论。它避免了制作临时文件并直接将矩阵填充到 rank 1 中。

标签: c++ mpi sparse-matrix eigen eigen3


【解决方案1】:

我一般建议使用压缩形式来传输稀疏矩阵。并且不需要将值复制到临时std::vectors。

void sendSparseEigen(const Ref<const SparseMatrix<double>,StandardCompressedFormat>& mat) {
    int rows=mat.rows, cols=mat.cols, nnz=mat.nonZeros();
    assert(rows==mat.innerSize() && cols==mat.outerSize());
    assert(mat.outerIndexPtr()[cols]==nnz);
    int shape[3] = {rows, cols, nnz};
    MPI_Send(shape              ,3   ,MPI_INT,   1, 100, MPI_COMM_WORLD);
    MPI_Send(mat.valuePtr()     ,nnz ,MPI_DOUBLE,1, 101, MPI_COMM_WORLD);
    MPI_Send(mat.innerIndexPtr(),nnz ,MPI_INT,   1, 102, MPI_COMM_WORLD);
    MPI_Send(mat.outerIndexPtr(),cols,MPI_INT,   1, 103, MPI_COMM_WORLD);
}

void receiveSparseEigen(SparseMatrix<double> &out){
    int shape[3];
    MPI_Recv(shape,3,MPI_INT,0, 100, MPI_COMM_WORLD, &status);
    int rows=shape[0], cols=shape[1], nnz=shape[2];
    out.resize(rows, cols);
    out.reserve(nnz);
    MPI_Recv(out.valuePtr(),  nnz, MPI_DOUBLE,0, 101, MPI_COMM_WORLD, &status);
    MPI_Recv(out.innerIndexPtr(),nnz, MPI_INT,0, 102, MPI_COMM_WORLD, &status);
    MPI_Recv(out.outerIndexPtr(),cols,MPI_INT,0, 103, MPI_COMM_WORLD, &status);
    out.outerIndexPtr()[cols] = nnz;
}

免责声明:我不是 MPI 专家,我从您的示例中复制了所有与 MPI 相关的代码——显然您应该以某种方式处理 MPI 生成的所有可能错误。并且上面的代码未经测试。

【讨论】:

  • 像魅力一样工作,虽然我没有明确测试速度/内存。很明显,您的解决方案避免了创建临时的以节省内存和冗余操作。谢谢!还有一件事,将来,如果其他人正在使用此解决方案,请确保在通过之前压缩稀疏矩阵。 mat.makeCompressed();
  • 没错,您实际上可以从Ref 中删除StandardCompressedFormat 标志,而只删除assert(mat.isCompressed()); 或者传递一个非常量SparseMatrix&amp; 并在第一个函数中调用makeCompressed()。跨度>
猜你喜欢
  • 1970-01-01
  • 2013-09-25
  • 2015-12-05
  • 1970-01-01
  • 2019-12-16
  • 2015-12-30
  • 2023-03-29
  • 2014-03-19
  • 1970-01-01
相关资源
最近更新 更多