在Eigen中填充稀疏矩阵非常慢

时间:2013-07-26 09:06:00

标签: c++ matrix eigen

我有这个代码在for循环中调用java中的c ++方法:

JNIEXPORT void JNICALL Java_com_jp_algi_CoreC_MMload(JNIEnv *env3, jobject clazz3, jdoubleArray inputv, jintArray inputi, jint poc, jint pozic)
{
    jdouble* fltv2 ;
    jint* fltind2;
    jsize sizedat = env3->GetArrayLength(inputi);
    fltv2  = new jdouble[sizedat];
    fltind2  = new jint[sizedat];
    jint i;
    jint jm;
    env3->GetIntArrayRegion(inputi,0,sizedat,fltind2);
    env3->GetDoubleArrayRegion(inputv,0,sizedat,fltv2);

    // default is column major
    matA.reserve(VectorXi::Constant(1,sizedat));

    for ( jm = 0; jm < sizedat; jm++) {
        //matA.insert(fltind2[jm],pozic) = fltv2[jm]; // alternative: mat.coeffRef(i,j) += v_ij;
        matA.insert(fltind2[jm],pozic)= fltv2[jm];
        //matA.insertBack(fltind2[jm],pozic)= fltv2[jm];
        //matA.ins
        //matA.insertBackUncompressed();
        //matA.coeffRef(fltind2[jm],pozic) += fltv2[jm];
        // optional
    }

    matA.makeCompressed();

    //k++; //blbe zayklenji!!!
    env3->SetIntArrayRegion(inputi,0,sizedat,fltind2);
    env3->SetDoubleArrayRegion(inputv,0,sizedat,fltv2);
    delete[] fltv2;
    delete[] fltind2;
}

其中inputv是matA列的值。和inputi是这些值的索引。

我在docs中读到了特征,插入函数是最快的,当非零系数的数量大约是5000时就可以了。但是当我有25000时,每列需要5秒!

我试过后退,但值是一样的吗?这个命令到底是做什么的?有没有办法改进这段代码?

一旦有利(也许):每列中的值和索引按从最高到最低的值排序......

2 个答案:

答案 0 :(得分:3)

如果稀疏矩阵很大,则必须在填充之前为matA分配足够的空间。否则,需要很长时间才能一次又一次地分配空间和复制数据。

您需要做的第一件事是了解矩阵的稀疏模式。稀疏模式的意思是每列的非零元素的数量(假设您的稀疏矩阵在列专业中)。如果我们将这些值存储在类型VectorXi的变量V中,则调用matA.reserve(V)将分配足够的内存空间。

按照上述步骤,我可以使用普通笔记本电脑在30秒内填充47236x677399稀疏矩阵(#non-zeros:49556258)。如果我不这样做,那就需要永远......

答案 1 :(得分:2)

Eigen Sparse Matrix Tutorial的重点:

1: SparseMatrix<double> mat(rows,cols);         // default is column major
2: mat.reserve(VectorXi::Constant(cols,x));
3: for each i,j such that v_ij != 0
4:   mat.insert(i,j) = v_ij;                    // alternative:  mat.coeffRef(i,j) += v_ij;
5: mat.makeCompressed();                        // optional

这里的关键因素是第2行,我们为每列保留x非零的空间。在许多情况下,可以容易地预先知道每列或每行的非零数。如果每个内部向量的变化很大,那么可以通过提供一个带有operator [](int j)的向量对象来为每个内向量指定一个保留大小,返回第j个内向量的保留大小(例如,通过VectorXi或std :: vector)。如果只能粗略估计每个内向量的非零数,则强烈建议高估它而不是相反。如果省略此行,则第一次插入新元素将为每个内部向量保留2个元素的空间。

第4行对Column major case执行排序插入。对于速度,当填充第j列时,现有的非零应该具有小于i的行索引。然后,这个操作归结为平凡的O(1)操作。

第5行抑制剩余的空白空间并将矩阵转换为压缩列存储。