我可以使用 Eigen 稀疏矩阵来满足一般存储要求吗
Can I use Eigen sparse matrices for general storage requirements
我需要一个模板化的稀疏矩阵实现,但只是为了减少内存占用,不进行任何数值求解。所以我尝试使用 Eigen,即使我不需要数学部分。为什么 ?它恰好在我的机器上,我已经用它来做其他事情了。但我肯定不是 Eigen 专家!
Context:我有一个类型 T
(比如 struct T{int a; float b; vector<int> c; };
,我需要存储它的大型矩阵(比如超过 1000x1000)和大多数的值是 null/irrelevant.
因为我不做任何数学运算,所以我认为提供一个赋值运算符来进行存储/检索操作就足够了,如下所示:
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 with -std=c++11)
问题:
- 可以用 Eigen 做到这一点吗?
- 如果是,我需要在数据类型中添加什么?这是最好的方法吗?
- 如果没有,您对另一个图书馆有什么建议吗?
相关 Eigen 手册页:
的确,因为它是为存储数值而设计的,所以你的类型应该是 constructible/assignable 来自文字 0
。需要确保 insert(i,j) returns 对初始化为 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+=
为了完成@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 );
}
我需要一个模板化的稀疏矩阵实现,但只是为了减少内存占用,不进行任何数值求解。所以我尝试使用 Eigen,即使我不需要数学部分。为什么 ?它恰好在我的机器上,我已经用它来做其他事情了。但我肯定不是 Eigen 专家!
Context:我有一个类型 T
(比如 struct T{int a; float b; vector<int> c; };
,我需要存储它的大型矩阵(比如超过 1000x1000)和大多数的值是 null/irrelevant.
因为我不做任何数学运算,所以我认为提供一个赋值运算符来进行存储/检索操作就足够了,如下所示:
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 with -std=c++11)
问题:
- 可以用 Eigen 做到这一点吗?
- 如果是,我需要在数据类型中添加什么?这是最好的方法吗?
- 如果没有,您对另一个图书馆有什么建议吗?
相关 Eigen 手册页:
的确,因为它是为存储数值而设计的,所以你的类型应该是 constructible/assignable 来自文字 0
。需要确保 insert(i,j) returns 对初始化为 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+=
为了完成@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 );
}