[Eigen中文文档] 扩展/自定义Eigen(二)

简介: CwiseNullaryOp 类的主要目的是定义过程矩阵,例如由Ones()、Zero()、Constant()、Identity()和Random()方法返回的常量或随机矩阵。然而,通过一些想象力,可以用最小的努力实现非常复杂的矩阵操作,因此很少需要实现新的表达式。

文档总目录

使用nullary-expressions操作矩阵

英文原文(Matrix manipulation via nullary-expressions)

CwiseNullaryOp 类的主要目的是定义过程矩阵,例如由Ones()Zero()Constant()Identity()Random()方法返回的常量或随机矩阵。然而,通过一些想象力,可以用最小的努力实现非常复杂的矩阵操作,因此很少需要实现新的表达式。

示例 1:循环矩阵

为了探索这些可能性,让我们从实现新表达式的循环矩阵示例开始。回想一下,循环矩阵是一个矩阵,其中每列与左侧的列相同,只是向下循环移位。例如,这是一个4x4的循环矩阵:
$$ \begin{bmatrix} 1&8&4&2 \\ 2&1&8&4 \\ 4&2&1&8 \\ 8&4&2&1 \end{bmatrix} $$
循环矩阵由其第一列唯一确定。我们希望编写一个函数 makeCirculant,在给定第一列的情况下,返回一个表示循环矩阵的表达式。

在这个练习中,makeCirculant的返回类型将是一个CwiseNullaryOp,我们需要用以下内容进行实例化:

  • 一个适当的circulant_functor,其中存储输入向量并实现适当的系数访问运算符(i,j)
  • 一个矩阵类的模板实例化,传递编译时信息,如标量类型,大小和首选存储布局。

ArgType 称为输入向量的类型,我们可以构造等效的平方 Matrix 类型,如下所示:

template <class ArgType>
Eigen::CwiseNullaryOp<circulant_functor<ArgType>, typename circulant_helper<ArgType>::MatrixType>
makeCirculant(const Eigen::MatrixBase<ArgType>& arg)
{
   
  typedef typename circulant_helper<ArgType>::MatrixType MatrixType;
  return MatrixType::NullaryExpr(arg.size(), arg.size(), circulant_functor<ArgType>(arg.derived()));
}

这个小辅助结构将帮助我们实现 makeCirculant 函数,如下所示:

template <class ArgType>
Eigen::CwiseNullaryOp<circulant_functor<ArgType>, typename circulant_helper<ArgType>::MatrixType>
makeCirculant(const Eigen::MatrixBase<ArgType>& arg)
{
   
  typedef typename circulant_helper<ArgType>::MatrixType MatrixType;
  return MatrixType::NullaryExpr(arg.size(), arg.size(), circulant_functor<ArgType>(arg.derived()));
}

函数采用 MatrixBase 作为参数(有关更多详细信息,请参阅此页)。然后,通过 DenseBase::NullaryExpr 静态方法以足够的运行时大小构造 CwiseNullaryOp 对象。

接下来,需要实现 circulant_functor,这是一个简单的练习:

template<class ArgType>
class circulant_functor {
   
  const ArgType &m_vec;
public:
  circulant_functor(const ArgType& arg) : m_vec(arg) {
   }

  const typename ArgType::Scalar& operator() (Eigen::Index row, Eigen::Index col) const {
   
    Eigen::Index index = row - col;
    if (index < 0) index += m_vec.size();
    return m_vec(index);
  }
};

现在我们已经准备好尝试我们的新功能了:

int main()
{
   
    Eigen::VectorXd vec(4);
    vec << 1, 2, 4, 8;
    Eigen::MatrixXd mat;
    mat = makeCirculant(vec);
    std::cout << mat << std::endl;
}

如果组合所有片段,则会产生以下输出,表明程序按预期工作:

1 8 4 2
2 1 8 4
4 2 1 8
8 4 2 1

makeCirculant 的这种实现比从头开始定义新表达式要简单得多。

示例 2:索引行和列

这里的目标是模仿 MatLab,使用两个索引向量分别引用要选取的行和列来索引矩阵,如下所示:

A =
 7  9 -5 -3
-2 -6  1  0
 6 -3  0  9
 6  6  3  9

A([1 2 1], [3 2 1 0 0 2]) =
 0  1 -6 -2 -2  1
 9  0 -3  6  6  0
 0  1 -6 -2 -2  1

为此,首先编写一个零元函数对象,存储对输入矩阵和两个索引数组的引用,并实现所需的operator() (i,j)

template<class ArgType, class RowIndexType, class ColIndexType>
class indexing_functor {
   
  const ArgType &m_arg;
  const RowIndexType &m_rowIndices;
  const ColIndexType &m_colIndices;
public:
  typedef Eigen::Matrix<typename ArgType::Scalar,
                 RowIndexType::SizeAtCompileTime,
                 ColIndexType::SizeAtCompileTime,
                 ArgType::Flags&Eigen::RowMajorBit?Eigen::RowMajor:Eigen::ColMajor,
                 RowIndexType::MaxSizeAtCompileTime,
                 ColIndexType::MaxSizeAtCompileTime> MatrixType;

  indexing_functor(const ArgType& arg, const RowIndexType& row_indices, const ColIndexType& col_indices)
    : m_arg(arg), m_rowIndices(row_indices), m_colIndices(col_indices)
  {
   }

  const typename ArgType::Scalar& operator() (Eigen::Index row, Eigen::Index col) const {
   
    return m_arg(m_rowIndices[row], m_colIndices[col]);
  }
};

然后,创建一个 indexing(A,rows,cols) 函数来创建这个零元表达式(nullary expression):

template <class ArgType, class RowIndexType, class ColIndexType>
Eigen::CwiseNullaryOp<indexing_functor<ArgType,RowIndexType,ColIndexType>, typename indexing_functor<ArgType,RowIndexType,ColIndexType>::MatrixType>
mat_indexing(const Eigen::MatrixBase<ArgType>& arg, const RowIndexType& row_indices, const ColIndexType& col_indices)
{
   
  typedef indexing_functor<ArgType,RowIndexType,ColIndexType> Func;
  typedef typename Func::MatrixType MatrixType;
  return MatrixType::NullaryExpr(row_indices.size(), col_indices.size(), Func(arg.derived(), row_indices, col_indices));
}

最后,这是一个如何使用该函数的示例:

Eigen::MatrixXi A = Eigen::MatrixXi::Random(4,4);
Eigen::Array3i ri(1,2,1);
Eigen::ArrayXi ci(6); ci << 3,2,1,0,0,2;
Eigen::MatrixXi B = mat_indexing(A, ri, ci);
std::cout << "A =" << std::endl;
std::cout << A << std::endl << std::endl;
std::cout << "A([" << ri.transpose() << "], [" << ci.transpose() << "]) =" << std::endl;
std::cout << B << std::endl;

这种简单的实现已经非常强大,因为行或列索引数组也可以是执行偏移、取模、跨步、反转等的表达式。

B =  mat_indexing(A, ri+1, ci);
std::cout << "A(ri+1,ci) =" << std::endl;
std::cout << B << std::endl << std::endl;
B =  mat_indexing(A, Eigen::ArrayXi::LinSpaced(13,0,12).unaryExpr([](int x){
   return x%4;}), Eigen::ArrayXi::LinSpaced(4,0,3));
std::cout << "A(ArrayXi::LinSpaced(13,0,12).unaryExpr([](int x){return x%4;}), ArrayXi::LinSpaced(4,0,3)) =" << std::endl;
std::cout << B << std::endl << std::endl;

输出如下:

A(ri+1,ci) =
 9  0 -3  6  6  0
 9  3  6  6  6  3
 9  0 -3  6  6  0

A(ArrayXi::LinSpaced(13,0,12).unaryExpr([](int x){
   return x%4;}), ArrayXi::LinSpaced(4,0,3)) =
 7  9 -5 -3
-2 -6  1  0
 6 -3  0  9
 6  6  3  9
 7  9 -5 -3
-2 -6  1  0
 6 -3  0  9
 6  6  3  9
 7  9 -5 -3
-2 -6  1  0
 6 -3  0  9
 6  6  3  9
 7  9 -5 -3
相关文章
|
算法 编译器 程序员
Windows下Boost库的安装与使用
Windows下Boost库的安装与使用
3866 0
Windows下Boost库的安装与使用
|
编译器
(9)Qt中信号与槽重载的解决方案
本文介绍了在Qt中处理信号与槽重载问题的三种解决方案:使用函数指针、Qt提供的QOverload类和Qt4的宏方式。
1038 3
|
算法 Unix 调度
【Qt 线程】深入探究QThread线程优先级:原理、应用与最佳实践
【Qt 线程】深入探究QThread线程优先级:原理、应用与最佳实践
1517 0
|
自然语言处理 区块链 Python
传统的序列模型CRF与HMM区别
传统的序列模型CRF与HMM区别
|
Linux 编译器 开发工具
在CentOS环境下升级GCC编译器的指南
总结:本文提供了一种方法来升级CentOS的GCC编译器,通过使用CentOS的软件集合和开发者工具集工具,可以比较平滑地进行升级。在整个过程中无需从源代码编译,这样既省去了复杂的编译过程,也避免了可能出现的与系统库不兼容的风险。请注意,使用第三方仓库可能会带来系统稳定性和安全性上的潜在影响。所有操作都应谨慎进行,并确保有相应的数据备份。
1477 19
|
机器学习/深度学习 编解码 缓存
通义万相首尾帧图模型一键生成特效视频!
本文介绍了阿里通义发布的Wan2.1系列模型及其首尾帧生视频功能。该模型采用先进的DiT架构,通过高效的VAE模型降低运算成本,同时利用Full Attention机制确保生成视频的时间与空间一致性。模型训练分为三个阶段,逐步优化首尾帧生成能力及细节复刻效果。此外,文章展示了具体案例,并详细说明了训练和推理优化方法。目前,该模型已开源。
1897 9
|
机器学习/深度学习 人工智能 自然语言处理
DeepMesh:3D建模革命!清华团队让AI自动优化拓扑,1秒生成工业级网格
DeepMesh 是由清华大学和南洋理工大学联合开发的 3D 网格生成框架,基于强化学习和自回归变换器,能够生成高质量的 3D 网格,适用于虚拟环境构建、动态内容生成、角色动画等多种场景。
1794 4
DeepMesh:3D建模革命!清华团队让AI自动优化拓扑,1秒生成工业级网格
|
传感器 资源调度 算法
时间序列分析中的状态估计:状态空间模型与卡尔曼滤波的隐状态估计
状态空间模型通过构建生成可观测数据的潜在未观测状态来进行时间序列分析,卡尔曼滤波为其核心,提供实时隐状态估计。本文深入探讨其理论基础与实践应用,涵盖线性及非线性系统的高级滤波算法(如EKF和UKF),并展示在运动目标跟踪等领域的具体应用,强调了参数调优和性能评估的重要性。
1044 11
时间序列分析中的状态估计:状态空间模型与卡尔曼滤波的隐状态估计
|
开发者
Qt异步实现事件的定时执行 - QTimer和QThread的联合使用
通过将QTimer和QThread结合使用,Qt开发者可以实现高效的异步定时任务执行。这种方法不仅可以提升应用程序的响应能力,还可以在复杂的多线程环境中保持代码的简洁和可维护性。希望本文的详细介绍和示例代码能够帮助您更好地理解和应用这一技术。
1206 14
Cmake生成指定vs版本的工程文件
本文简单总结了使用 cmake 生成 visual studio 工程文件的过程

热门文章

最新文章