我可以将Eigen稀疏矩阵用于一般存储要求

时间:2016-06-07 14:59:47

标签: c++ matrix sparse-matrix eigen

我需要一个模板化的稀疏矩阵实现,但只是为了减少内存占用,进行任何数值求解。所以我尝试使用Eigen,即使我不需要数学部分。为什么?它碰巧躺在我的机器上,我已经用它来做其他东西了。但我肯定不是本征专家!

上下文:我有一个类型T(比如说​​struct T{int a; float b; vector<int> c; };,我需要存储大的这个矩阵(比如超过1000x1000)并且大多数值为null /无关。

由于我不做任何数学计算,但我提供一个分配操作员来进行存储/检索操作就足够了,如下所示:

int main()
{
    Eigen::SparseMatrix<MyClass> mat(1000,1000); // 1000000 elements
    MyClass b{ 5, 1.2 };
    mat.insert( 3, 4 ) = b;
}

所以这是一个数据类型,我认为是必要的:

struct MyClass
{
    int a;
    float b;
    std::vector<int> v_things;

    MyClass( int aa, float bb ) : a(aa), b(bb) {}
    MyClass( const MyClass& other ) // copy constructor
    {
        a = other.a;
        b = other.b;
        v_things = other.v_things;
    }
    MyClass& operator=( const MyClass& arg )
    {
        if( this != &arg )
        {
            MyClass tmp(arg);
            std::swap( tmp, *this );
        }
        return *this;
    }
};

但这无法编译,因为它似乎要求一些特殊形式的赋值运算符:

/usr/include/eigen3/Eigen/src/SparseCore/SparseMatrix.h:1146:27: error: no match for ‘operator=’ (operand types are ‘Eigen::internal::CompressedStorage<MyClass, int>::Scalar {aka MyClass}’ and ‘int’)
    return (m_data.value(p) = 0);'

(编译器:GCC 5.3,带-std = c ++ 11)

问题

  • 有可能用Eigen做到这一点吗?
    • 如果是,我需要添加什么数据类型?这是最好的方法吗?
    • 如果不是,你会对另一个图书馆有什么建议吗?

相关的本征手册页:

2 个答案:

答案 0 :(得分:5)

实际上,由于它是为存储数值而设计的,因此您的类型应该是文字0的可构造/可分配的。需要确保insert(i,j)返回对初始化为0的标量的引用。

因此,您可以通过添加虚拟operator=

来解决此问题
 MyClass& operator=(int x) { assert(x==0); /* ... */ return *this; }

修改

要使用setFromTriplets,您还需要提供operator+=。原因是默认情况下,重复的条目汇总在一起。在Eigen 3.3中,将仿函数(例如,lambda)传递给setFromTriplets来定义重复应该如何合并是更清晰的。在您的情况下,如果调用它,您可以传递一个触发运行时断言的仿函数:

mat.setFromTriplets(begin,end, [] (const MyClass& a,const MyClass &) {
    assert(false && "found duplicates"); return a; } );

在这种情况下,您无需定义MyClass::operator+=

答案 1 :(得分:0)

要完成@ggael给出的答案以及那些想要做类似事情的人,这里有一个完整的示例编译和运行:

#include <eigen3/Eigen/SparseCore>
#include <vector>
#include <iostream>
struct MyClass
{
    int a;
    float b;
    std::vector<int> v;

    MyClass(){}
    MyClass( int aa, float bb ) : a(aa), b(bb) {}
    MyClass( int aa): a(aa) {}
    MyClass( const MyClass& other ) // copy constructor
    {
        a = other.a;
        b = other.b;
        v = other.v;
    }
    MyClass& operator=( int x )
    {
        assert( x==0 );
        return *this;
    }

    MyClass& operator += ( const MyClass& x )
    {
        return *this;
    }
};

void PrintMat( const Eigen::SparseMatrix<MyClass>& mat )
{
    std::cout << "Matrix content:\n";
    for (int k=0; k<mat.outerSize(); ++k )
        for( Eigen::SparseMatrix<MyClass>::InnerIterator it(mat,k); it; ++it )
            std::cout << "row=" << it.row() << " col=" << it.col()
                << ": a=" << it.value().a
                << " b=" << it.value().b
                << " vect size=" << it.value().v.size() << "\n";
}

int main()
{
    Eigen::SparseMatrix<MyClass> mat(1000,1000); // 1000000 positions

    MyClass a{ 5, 1.2 };
    a.v.resize(5);
    mat.insert( 3, 4 ) = a;   // insert single element
    PrintMat( mat );

    MyClass b{ 6, 2.3 };
    b.v.resize(9);
    mat.coeffRef( 3, 4 ) = b; // update single element
    PrintMat( mat );

    std::vector<Eigen::Triplet<MyClass>> tripletList;
    for(int i=0; i<10; i++)
    {
        MyClass a{i*2,i*3.0f};
        tripletList.push_back( Eigen::Triplet<MyClass>(i,i*10,a) );
    }
    mat.setFromTriplets(tripletList.begin(), tripletList.end());
    PrintMat( mat );
}