[Eigen中文文档] 高级初始化

简介: 本文介绍了几种用于初始化矩阵的高级方法。提供了有关之前介绍的逗号初始化程序的更多详细信息。还解释了如何获得特殊矩阵,例如单位矩阵和零矩阵。

专栏总目录

英文原文(Advanced initialization)

本文介绍了几种用于初始化矩阵的高级方法。提供了有关之前介绍的逗号初始化程序的更多详细信息。还解释了如何获得特殊矩阵,例如单位矩阵和零矩阵。

逗号初始化

Eigen提供了一个逗号初始化语法,这让用户可以很容易的设置矩阵、向量、数组的系数。仅仅需要简单的列出系数,从左上角开始,从左到右,从上到下依次列出系数。初始化对象的大小需要提前指定,如果给的系数太多或太少,Eigen会报错,如下:

Matrix3f m;
m << 1, 2, 3,
     4, 5, 6,
     7, 8, 9;
std::cout << m;

输出:

1 2 3
4 5 6
7 8 9

此外,初始化列表的元素本身可以是向量或者矩阵。逗号就是把向量和矩阵连接起来。例如,下面是在指定向量大小后,连接两个向量(注意,必须先设置大小,然后才能使用逗号初始化)。

RowVectorXd vec1(3);
vec1 << 1, 2, 3;
std::cout << "vec1 = " << vec1 << std::endl;

RowVectorXd vec2(4);
vec2 << 1, 4, 9, 16;
std::cout << "vec2 = " << vec2 << std::endl;

RowVectorXd joined(7);
joined << vec1, vec2;
std::cout << "joined = " << joined << std::endl;

输出:

vec1 = 1 2 3
vec2 =  1  4  9 16
joined =  1  2  3  1  4  9 16

也可以使用同样的技术来初始化具有块结构的矩阵。

MatrixXf matA(2, 2);
matA << 1, 2, 3, 4;
MatrixXf matB(4, 4);
matB << matA, matA/10, matA/10, matA;
std::cout << matB << std::endl;

输出:

  1   2 0.1 0.2
  3   4 0.3 0.4
0.1 0.2   1   2
0.3 0.4   3   4

逗号初始化同样也可以填充块表达式如m.row(i),下面使用一个更加复杂的方式来实现第一个示例:

Matrix3f m;
m.row(0) << 1, 2, 3;
m.block(1,0,2,2) << 4, 5, 7, 8;
m.col(2).tail(2) << 6, 9;                   
std::cout << m;

输出:

1 2 3
4 5 6
7 8 9

特殊矩阵和数组

matrixarray类有如Zero()之类的静态方法,可用于将所有系数初始化为零。

共有三种重载,第一个重载不需要任何参数,仅可以用在固定大小的对象。如果想要一个动态大小的对象,需要指定大小。因此,第二个重载需要一个参数用来初始化一维动态对象。第三个重载,需要两个参数用来初始化二维对象的大小。所有的重载解释如下:

std::cout << "A fixed-size array:\n";
Array33f a1 = Array33f::Zero();
std::cout << a1 << "\n\n";


std::cout << "A one-dimensional dynamic-size array:\n";
ArrayXf a2 = ArrayXf::Zero(3);
std::cout << a2 << "\n\n";


std::cout << "A two-dimensional dynamic-size array:\n";
ArrayXXf a3 = ArrayXXf::Zero(3, 4);
std::cout << a3 << "\n";

输出:

A fixed-size array:
0 0 0
0 0 0
0 0 0

A one-dimensional dynamic-size array:
0
0
0

A two-dimensional dynamic-size array:
0 0 0 0
0 0 0 0
0 0 0 0

类似的,静态方法Constant(value)把所有系数都初始化为value。如果对象的大小需要指定,除了value参数还需要额外的参数,如 MatrixXd::Constant(rows, cols, value)

方法Random()用随机的数字填充矩阵或阵列。

使用Identity()获取单位矩阵,这只能用于matrix而不能用于vector,因为单位矩阵的概念是线性代数中的。

方法LinSpaced(size,low,high)只对向量和一维数组有效,它产生一个指定大小在lowhigh的等差数列。下面的例子解释LinSpaced(),打印一个表格,包含角度和弧度的对应值,以及他们的sincos值。

ArrayXXf table(10, 4);
table.col(0) = ArrayXf::LinSpaced(10, 0, 90);
table.col(1) = M_PI / 180 * table.col(0);
table.col(2) = table.col(1).sin();
table.col(3) = table.col(1).cos();
std::cout << "  Degrees   Radians      Sine    Cosine\n";
std::cout << table << std::endl;

输出:

Degrees   Radians      Sine    Cosine
        0         0         0         1
       10     0.175     0.174     0.985
       20     0.349     0.342      0.94
       30     0.524       0.5     0.866
       40     0.698     0.643     0.766
       50     0.873     0.766     0.643
       60      1.05     0.866       0.5
       70      1.22      0.94     0.342
       80       1.4     0.985     0.174
       90      1.57         1 -4.37e-08

此示例表明可以将像 LinSpaced() 这样的对象分配给变量(或表达式)。Eigen定义了诸如 setZero()MatrixBase::setIdentity()DenseBase::setLinSpaced() 之类的函数来执行此操作。下面的例子对比了三种方法来构造矩阵 $J = \begin{bmatrix} O & I \\ I & O \\ \end{bmatrix}$:

const int size = 6;
MatrixXd mat1(size, size);
mat1.topLeftCorner(size/2, size/2)     = MatrixXd::Zero(size/2, size/2);
mat1.topRightCorner(size/2, size/2)    = MatrixXd::Identity(size/2, size/2);
mat1.bottomLeftCorner(size/2, size/2)  = MatrixXd::Identity(size/2, size/2);
mat1.bottomRightCorner(size/2, size/2) = MatrixXd::Zero(size/2, size/2);
std::cout << mat1 << std::endl << std::endl;

MatrixXd mat2(size, size);
mat2.topLeftCorner(size/2, size/2).setZero();
mat2.topRightCorner(size/2, size/2).setIdentity();
mat2.bottomLeftCorner(size/2, size/2).setIdentity();
mat2.bottomRightCorner(size/2, size/2).setZero();
std::cout << mat2 << std::endl << std::endl;

MatrixXd mat3(size, size);
mat3 << MatrixXd::Zero(size/2, size/2), MatrixXd::Identity(size/2, size/2),
        MatrixXd::Identity(size/2, size/2), MatrixXd::Zero(size/2, size/2);
std::cout << mat3 << std::endl;

输出:

0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0

0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0

0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0

可以在 快速参考指南 中找到所有预定义矩阵、向量和数组对象的摘要。

用作临时对象

如上所示,Zero()Constant() 等静态方法可以在声明时或在赋值符右侧初始化变量。可以认为这些方法返回一个矩阵或数组,实际上,它们返回所谓的表达式对象,该对象在需要的时候才被计算,所以这样的语法不会产生任何额外开销。

这些表达式也可以用作临时对象。如下是 入门 章节的第二个示例,其说明了这个特性:

#include <iostream>
#include <Eigen/Dense>

using Eigen::MatrixXd;
using Eigen::VectorXd;

int main()
{
   
  MatrixXd m = MatrixXd::Random(3,3);
  m = (m + MatrixXd::Constant(3,3,1.2)) * 50;
  std::cout << "m =" << std::endl << m << std::endl;
  VectorXd v(3);
  v << 1, 2, 3;
  std::cout << "m * v =" << std::endl << m * v << std::endl;
}

输出:

m =
  94 89.8 43.5
49.4  101 86.8
88.3 29.8 37.8
m * v =
404
512
261

表达式 m + MatrixXf::Constant(3,3,1.2) 构造了一个 3*3 的矩阵,其元素全为1.2+m

逗号初始化也可以构造临时对象,下面的例子构造了一个2*3的随机矩阵,然后与矩阵 $\begin{bmatrix} 0 & 1 \\ 1 & 0 \\ \end{bmatrix}$ 相乘。

MatrixXf mat = MatrixXf::Random(2, 3);
std::cout << mat << std::endl << std::endl;
mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat;
std::cout << mat << std::endl;

输出:

 0.68  0.566  0.823
-0.211  0.597 -0.605

-0.211  0.597 -0.605
  0.68  0.566  0.823

在完成临时子矩阵的逗号初始化之后,这里需要使用finished()方法来获得实际的矩阵对象。

相关文章
|
8月前
|
编译器 索引
[Eigen中文文档] 块操作
本文介绍了块操作。块是matrix或array的部分矩形元素。块表达式既可以用作右值也可以用作左值。与Eigen表达式一样,如果让编译器进行优化,则块操作的运行时间成本为零。
65 0
|
8月前
|
存储 编译器
[Eigen中文文档] 深入了解 Eigen - 类层次结构
本页面介绍了Eigen类层次结构中 Core 类的设计及其相互关系。一般用户可能不需要关注这些细节,但对于高级用户和Eigen开发人员可能会有用。
134 0
|
8月前
|
存储 算法 NoSQL
[Eigen中文文档] 存储顺序
矩阵和二维数组有两种不同的存储顺序:列优先和行优先。本节解释了这些存储顺序以及如何指定应该使用哪一种。
76 0
|
8月前
[Eigen中文文档] 编写以特征类型为参数的函数(一)
Eigen使用表达式模板的方式导致每个表达式的类型可能都不同。如果将这样的表达式传递给一个需要Matrix类型参数的函数,则表达式将隐式地被评估为一个临时Matrix,然后再传递给函数。这意味着失去了表达式模板的好处。
82 0
|
8月前
|
存储 安全 编译器
[Eigen中文文档] 常见的陷阱
本文将介绍一些Eigen常见的陷阱
102 0
|
8月前
|
存储 C语言 C++
|
8月前
|
存储 编译器
|
8月前
|
存储 对象存储 索引
[Eigen中文文档] 扩展/自定义Eigen(二)
CwiseNullaryOp 类的主要目的是定义过程矩阵,例如由Ones()、Zero()、Constant()、Identity()和Random()方法返回的常量或随机矩阵。然而,通过一些想象力,可以用最小的努力实现非常复杂的矩阵操作,因此很少需要实现新的表达式。
70 0
|
8月前
|
存储 索引
[Eigen中文文档] 扩展/自定义Eigen(三)
本页面针对非常高级的用户,他们不害怕处理一些Eigen的内部细节。在大多数情况下,可以通过使用自定义一元或二元函数避免使用自定义表达式,而极其复杂的矩阵操作可以通过零元函数(nullary-expressions)来实现,如前一页所述。 本页面通过示例介绍了如何在Eigen中实现新的轻量级表达式类型。它由三个部分组成:表达式类型本身、包含有关表达式编译时信息的特性类和评估器类,用于将表达式评估为矩阵。
70 1
|
8月前
|
测试技术 API C++
[Eigen中文文档] 扩展/自定义Eigen(一)
在本节中,将介绍如何向MatrixBase添加自定义方法。由于所有表达式和矩阵类型都继承自MatrixBase,因此将方法添加到MatrixBase会立即使其对所有表达式可用!一个典型的用例是,使Eigen与另一个API兼容。
118 0

热门文章

最新文章