[Eigen中文文档] Array类与元素操作

简介: 与Matrix类用于线性代数计算不同的是,Array类提供了通用目的数组。此外,Array类提供了一种执行按系数运算的简单方法,这可能没有线性代数意义,例如对每一个元素都加一个常数或按系数将两个数组相乘。

专栏总目录

英文原文(The Array class and coefficient-wise operations)

本页旨在提供有关如何使用EigenArray类的概述和说明。

什么是Array类?

Matrix类用于线性代数计算不同的是,Array类提供了通用目的数组。此外,Array类提供了一种执行按系数运算的简单方法,这可能没有线性代数意义,例如对每一个元素都加一个常数或按系数将两个数组相乘。

Array类型

Array是一个类模板,采用与Matrix相同的模板参数。与Matrix一样,前三个模板参数是必需的:

Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>

最后三个模板参数是可选的。由于这与Matrix完全相同,因此不再在此解释,仅参考Matrix 类

Eigen还提供了一些常见的类型定义,其方式类似于Matrix类型定义,但有一些细微差别,因为Array一词用于一维和二维数组。使用ArrayNt代表一维N个大小的标量,其中 N 和 t 是大小和标量类型,详见矩阵与向量运算。对于二维数组类型,使用 ArrayNNt表示。示例如下:

类型 类型定义
Array ArrayXf
Array Array3f
Array ArrayXXd
Array Array33d

访问Array中的值

就像矩阵一样,使用括号运算符可以访问数组中的值。另外,<<运算符可用于初始化数组(使用逗号初始化)或打印它们。

例如:

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

int main()
{
   
  Eigen::ArrayXXf  m(2,2);

  // assign some values coefficient by coefficient
  m(0,0) = 1.0; m(0,1) = 2.0;
  m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0);

  // print values to standard output
  std::cout << m << std::endl << std::endl;

  // using the comma-initializer is also allowed
  m << 1.0,2.0,
       3.0,4.0;

  // print values to standard output
  std::cout << m << std::endl;
}

输出如下:

1 2
3 5

1 2
3 4

有关逗号初始化的更多信息,请参阅高级初始化

加法与减法

两个数组的加减法与矩阵相同。如果两个数组的大小相同,并且加法或减法是按系数进行的,则该操作有效。

Array 还支持 array + scalar 的表达形式,这实现了对数组的每个系数都加一个常数。并且这是在Matrix类中不能直接使用的功能。

示例如下:

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

int main()
{
   
  Eigen::ArrayXXf a(3,3);
  Eigen::ArrayXXf b(3,3);
  a << 1,2,3,
       4,5,6,
       7,8,9;
  b << 1,2,3,
       1,2,3,
       1,2,3;

  // Adding two arrays
  std::cout << "a + b = " << std::endl << a + b << std::endl << std::endl;

  // Subtracting a scalar from an array
  std::cout << "a - 2 = " << std::endl << a - 2 << std::endl;
}

输出如下:

a + b = 
 2  4  6
 5  7  9
 8 10 12

a - 2 = 
-1  0  1
 2  3  4
 5  6  7

Array乘法

当然你可以将一个数组乘以一个标量,这与矩阵相同。数组与矩阵不同的地方在于自身相乘,矩阵将乘法解释为矩阵乘积,而数组将乘法解释为系数乘积。因此,两个数组相乘时它们必须具有相同的维度。

示例如下:

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

int main()
{
   
  Eigen::ArrayXXf a(2,2);
  Eigen::ArrayXXf b(2,2);
  a << 1,2,
       3,4;
  b << 5,6,
       7,8;
  std::cout << "a * b = " << std::endl << a * b << std::endl;
}

输出如下:

a * b = 
 5 12
21 32

其他按元素操作的运算

除了上述的加法、减法和乘法运算符之外,Array 类还定义了其他按系数计算的运算。例如,abs() 方法对每个元素取绝对值,而sqrt()计算每个系数的平方根。如果你有两个相同大小的数组,你可以调用min(.)来构造一个数组,其元素是两个给定数组对应元素的最小值。这些操作在以下示例中进行了说明:

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

int main()
{
   
  Eigen::ArrayXf a = Eigen::ArrayXf::Random(5);
  a *= 2;
  std::cout << "a =" << std::endl
            << a << std::endl;
  std::cout << "a.abs() =" << std::endl
            << a.abs() << std::endl;
  std::cout << "a.abs().sqrt() =" << std::endl
            << a.abs().sqrt() << std::endl;
  std::cout << "a.min(a.abs().sqrt()) =" << std::endl
            << a.min(a.abs().sqrt()) << std::endl;
}

输出如下:

a =
  1.36
-0.422
  1.13
  1.19
  1.65
a.abs() =
 1.36
0.422
 1.13
 1.19
 1.65
a.abs().sqrt() =
1.17
0.65
1.06
1.09
1.28
a.min(a.abs().sqrt()) =
  1.17
-0.422
  1.06
  1.09
  1.28

array和matrix表达式之间的转换

什么时候应该使用Matrix 类的对象,什么时候应该使用 Array 类的对象呢?

首先, Matrix 类和Array类的方法不通用。如果需要进行线性代数运算,例如矩阵乘法,那么应该使用 Matrix 类;如果需要做元素运算,那么应该使用Array类。然而,有时并没有那么简单,而是需要同时使用Matrix 类和Array类。这种情况下,需要将Matrix 转换为Array或相反。这样就可以使用所有操作,而不管对象声明为Matrix 还是Array

Matrix 类有一个 .array() 方法可以将Matrix 转换为Array。同样,Array有一个 .matrix() 方法。由于Eigen表达式的抽象,这些转换发生在编译的时候,所以不需要任何运行时间成本。.array().matrix()既可以作为左值,也可以作为右值。

Eigen 禁止在表达式中混合使用MatrixArray。例如,不能将MatrixArray直接相加;运算符的操作对象要么都是Matrix,要么都是Array,但转换后是可以的。此规则的例外是赋值运算符,允许将Matrix 赋值给Array,或将将 Array 赋值给Matrix

以下示例展示了如何通过使用.array()方法对 Matrix 对象使用Array的方法。例如,语句 result = m.array() * n.array() 将两个矩阵mn都转换为数组,并使它们按系数相乘,再将结果分配给矩阵变量(这是合法的,因为Eigen允许将数组表达式赋值给矩阵变量)。

事实上,这种用例非常普遍,以至于Eigen为矩阵提供了一个 const .cwiseProduct(.) 方法来满足按元素相乘的需求。

示例如下:

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

using Eigen::MatrixXf;

int main()
{
   
  MatrixXf m(2,2);
  MatrixXf n(2,2);
  MatrixXf result(2,2);

  m << 1,2,
       3,4;
  n << 5,6,
       7,8;

  result = m * n;
  std::cout << "-- Matrix m*n: --\n" << result << "\n\n";
  result = m.array() * n.array();
  std::cout << "-- Array m*n: --\n" << result << "\n\n";
  result = m.cwiseProduct(n);
  std::cout << "-- With cwiseProduct: --\n" << result << "\n\n";
  result = m.array() + 4;
  std::cout << "-- Array m + 4: --\n" << result << "\n\n";
}

输出如下:

-- Matrix m*n: --
19 22
43 50

-- Array m*n: --
 5 12
21 32

-- With cwiseProduct: --
 5 12
21 32

-- Array m + 4: --
5 6
7 8

同样,如果array1array2是数组,则表达式array1.matrix() * array2.matrix()可以计算他们的矩阵乘积。

接下来是一个更复杂一点的示例,表达式(m.array() + 4).matrix() * m对每一个元素都加4,然后计算表达式结果与矩阵m的矩阵乘积。类似的,表达式(m.array() * n.array()).matrix() * m按元素计算矩阵mn的乘积,然后计算其结果与m的矩阵乘法。

示例如下:

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

using Eigen::MatrixXf;

int main()
{
   
  MatrixXf m(2,2);
  MatrixXf n(2,2);
  MatrixXf result(2,2);

  m << 1,2,
       3,4;
  n << 5,6,
       7,8;

  result = (m.array() + 4).matrix() * m;
  std::cout << "-- Combination 1: --\n" << result << "\n\n";
  result = (m.array() * n.array()).matrix() * m;
  std::cout << "-- Combination 2: --\n" << result << "\n\n";
}

输出如下:

-- Combination 1: --
23 34
31 46

-- Combination 2: --
 41  58
117 170
相关文章
|
1月前
|
SQL XML Java
<foreach>元素中collection=list改成collection=array
<foreach>元素中collection=list改成collection=array
|
8月前
|
分布式计算 MaxCompute
在MaxCompute中,如果你想知道一个数组(Array)中有多少个元素
在MaxCompute中,如果你想知道一个数组(Array)中有多少个元素
94 1
|
JavaScript
js:Array数组插入元素操作的4种方式
js:Array数组插入元素操作的4种方式
128 0
|
Python
numpy重新学习系列(7)---如何用np.ones_like创建一个新的和原来array形状一样的,但是元素为1的新的array
numpy重新学习系列(7)---如何用np.ones_like创建一个新的和原来array形状一样的,但是元素为1的新的array
88 0
numpy重新学习系列(7)---如何用np.ones_like创建一个新的和原来array形状一样的,但是元素为1的新的array
|
Python
numpy重新学习系列(5)---如何用np.zeros_like创建一个新的和原来array形状一样的,但是元素为0的新的array
numpy重新学习系列(5)---如何用np.zeros_like创建一个新的和原来array形状一样的,但是元素为0的新的array
99 0
numpy重新学习系列(5)---如何用np.zeros_like创建一个新的和原来array形状一样的,但是元素为0的新的array
|
Java 索引
【重学Javase】—— 数组(从头剖析一维数组,二维数组,array常用工具类以及数组的两种常见异常)
【重学Javase】—— 数组(从头剖析一维数组,二维数组,array常用工具类以及数组的两种常见异常)
123 0
【重学Javase】—— 数组(从头剖析一维数组,二维数组,array常用工具类以及数组的两种常见异常)
|
JavaScript 前端开发
【笔记】HTMLCollection拿不到元素?无法转Array?
HTMLCollection拿不到元素?无法转Array?
382 0
【笔记】HTMLCollection拿不到元素?无法转Array?
|
Python
numpy重新学习系列(6)---如何用np.ones创建一个新的array,里面元素是1
numpy重新学习系列(6)---如何用np.ones创建一个新的array,里面元素是1
52 0
|
Python
numpy重新学习系列(4)---如何用np.zeros创建填充元素为0的array
numpy重新学习系列(4)---如何用np.zeros创建填充元素为0的array
82 0
|
存储 并行计算 供应链
使用 PolarDB 开源版 采用array数组和gin索引高效率解决用户画像、实时精准营销类业务需求
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍使用 PolarDB 开源版高效率解决用户画像、实时精准营销类业务需求
256 0