稠密对称矩阵的特征有效型
Eigen efficient type for dense symmetric matrix
对于存储密集、固定大小的对称矩阵,Eigen是否具有有效类型?(嘿,它们无处不在!)
即,对于N=9,它应该只存储(1+9)*9/2==45个元素,并且它有适当的操作。例如,应该有两个对称矩阵的有效加法,它返回simmilar对称矩阵。
如果没有这样的东西,我应该采取什么行动(看起来像这样)将这种类型引入到Eigen?它有"观点"的概念吗?我能为我自己的类型写一些类似"矩阵视图"的东西吗?这会使它成为Eigen friednly?
附言:也许我可以使用map将普通数组视为1xN矩阵,并对其进行操作。但这不是最干净的解决方案。
对称矩阵的压缩存储是矢量化代码(即速度)的大敌人。标准做法是将相关的N*(N+1)/2系数存储在全密NxN矩阵的上三角部分或下三角部分中,并使剩余的(N-1)*N/2不被引用。对称矩阵上的所有运算都是通过考虑这种特殊的存储来定义的。在本征中,你有三角形和自伴随视图的概念来获得这个。
从本征参考:(对于实矩阵自伴随==对称)。
就像三角形矩阵一样,你可以引用任何三角形部分将其视为自伴随矩阵,并执行特殊和优化的操作。同样是相对的三角形部分从不被引用,并且可以用于存储其他信息。
除非内存是个大问题,否则我建议将矩阵的未引用部分留空。(代码可读性更强,没有性能问题。)
是的,本征3有视图的概念。不过,它对存储没有任何作用。不过,作为一个想法,您可能能够为两个相同类型的对称矩阵共享一个更大的块:
Matrix<float,4,4> A1, A2; // assume A1 and A2 to be symmetric
Matrix<float,5,4> A;
A.topRightCorner<4,4>().triangularView<Upper>() = A1;
A.bottomLeftCorner<4,4>().triangularView<Lower>() = A2;
不过它很笨重,只有当你的记忆力真的很珍贵的时候,我才会使用它。
对称矩阵的有效类型
您只需将值分配给矩阵的下/上三角形部分,并使用特征三角形和自伴视图。然而,我已经在小的固定大小矩阵上测试了这两种情况。我注意到,从性能角度来看,使用视图并不总是最佳选择。考虑以下代码:
Eigen::Matrix2d m;
m(0,0) = 2.0;
m(1,0) = 1.0;
// m(0,1) = 1.0;
m(1,1) = 2.0;
Eigen::Vector2d v;
v << 1.0,1.0;
auto result = m.selfadjointView<Eigen::Lower>()*v;
与下面给出的替代解决方案相比,最后一行中的乘积相当慢(在我的情况下,double 2x2
矩阵慢约20%)。(通过取消对m(0,1) = 1.0;
的注释并使用auto result = m*v
,使用完整矩阵的乘积对于double 2x2
矩阵来说甚至更快)。
一些替代方案
1)将对称矩阵存储在向量中
您可以将矩阵存储在大小为45的向量中。用矢量格式求2个矩阵的和很简单(只需求矢量的和)。但是您必须为产品编写自己的实现。
这里是这样一个matrix * vector
乘积(密集、固定大小)的实现,其中矩阵的下部按列存储在向量中:
template <typename T, size_t S>
Eigen::Matrix<T,S,1> matrixVectorTimesVector(const Eigen::Matrix<T,S*(S+1)/2,1>& m, const Eigen::Matrix<T,S,1>& v)
{
Eigen::Matrix<T,S,1> ret(Eigen::Matrix<T,S,1>::Zero());
int counter(0);
for (int i=0; i<S; ++i)
{
ret[i] += m(counter++)*v(i);
for (int j=i+1; j<S; ++j)
{
ret[i] += m(counter)*v(j);
ret[j] += m(counter++)*v(i);
}
}
return ret;
}
2)只存储三角形部分并执行自己的操作
当然,您也可以实现自己的产品matrix * vector
,其中矩阵只存储45个元素(假设我们存储下三角部分)。这可能是最优雅的解决方案,因为它保持了矩阵的格式(而不是使用表示矩阵的向量)。然后你也可以像下面的例子一样使用特征函数:
template <typename T, size_t S>
Eigen::Matrix<T,S,S> symmMatrixPlusSymmMatrix( Eigen::Matrix<T,S,S>& m1, const Eigen::Matrix<T,S,S>& m2)
{
Eigen::Matrix<T,S,S> ret;
ret.template triangularView<Eigen::Lower>() = m1 + m2; // no performance gap here!
return ret;
}
在上面的函数(2个对称矩阵的和)中,只访问m1和m2的下三角部分。请注意,triangularView
在这种情况下没有表现出性能差距(我根据我的基准测试确认了这一点)。
关于matrix * vector
产品,请参见以下示例(性能与备选方案1中的产品相同)。该算法只访问矩阵的下三角部分。
template <typename T, size_t S>
Eigen::Matrix<T,S,1> symmMatrixTimesVector(const Eigen::Matrix<T,S,S>& m, const Eigen::Matrix<T,S,1>& v)
{
Eigen::Matrix<T,S,1> ret(Eigen::Matrix<T,S,1>::Zero());
int counter(0);
for (int c=0; c<S; ++c)
{
ret(c) += m(c,c)*v(c);
for (int r=c+1; r<S; ++r)
{
ret(c) += m(r,c)*v(r);
ret(r) += m(r,c)*v(c);
}
}
return ret;
}
在我的情况下,与使用全矩阵(2x2=4个元素)的产品相比,产品Matrix2d*Vector2d
的性能增益为10%。
- 如何创建value_type型特征?
- 以特征类型作为参数的泛型函数回调
- 传递非泛型函数的最有效方法是什么?
- 是否存在将长整型转换为指针有效的情况
- 找到稀疏矩阵(特征)最大值的有效方法
- 有没有一种有效的方法来删除已分配但空的特征行而不重新分配
- C++模板特征以指定任何无符号整型
- C# 泛型 - 基于类型特征的重载
- 具有从特定范围的随机数初始化特征矩阵或向量初始化特征矩阵或向量的有效方法
- 为什么这C++检测T型是否具有空运算符(EDT const&)失败的特征?
- 稠密对称矩阵的特征有效型
- 持有多个特征矩阵Xd的最有效方式
- 如何在特征中有效地使用逆和行列式
- 使用特征矩阵构建3D结构的最有效选项
- 如何专门化模板类方法基于类型特征?使用std::enable_if对非类函数有效,但对类方法无效
- 特征稀疏valuePtr显示零,同时省略有效值
- 为泛型函数定义自定义迭代器特征
- 我可以通过类型特征确定指针是否为整型
- 我可以声明一个未知类型的特征矩阵吗,或者至少声明一个泛型矩阵并稍后实例化吗
- 对称正定矩阵的特征有效逆