Eigen入门之密集矩阵 3 - Array操作

最后都变了- 提交于 2020-02-20 08:16:24

简介

在Eigen内,有Matrix,vector进行线性代数的相关运算,但也需要执行对矩阵内的系数的相关操作时,这是正常的功能需求。Eigen中的Array类就是满足此需求的。

Array 定义

和前面介绍的Matrix和Vector类似,Array类也是一个模板类

/** \class Array
  * \ingroup Core_Module
  *
  * \brief General-purpose arrays with easy API for coefficient-wise operations
  *
  * The %Array class is very similar to the Matrix class. It provides
  * general-purpose one- and two-dimensional arrays. The difference between the
  * %Array and the %Matrix class is primarily in the API: the API for the
  * %Array class provides easy access to coefficient-wise operations, while the
  * API for the %Matrix class provides easy access to linear-algebra
  * operations.
  *
  * See documentation of class Matrix for detailed information on the template parameters
  * storage layout.
  *
  * This class can be extended with the help of the plugin mechanism described on the page
  * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN.
  *
  * \sa \blank \ref TutorialArrayClass, \ref TopicClassHierarchy
  */
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
class Array
  : public PlainObjectBase<Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >

同样,Eigen也使用macro为Array定义了一些快捷简单Array类型。如下:


/** \defgroup arraytypedefs Global array typedefs
  * \ingroup Core_Module
  *
  * Eigen defines several typedef shortcuts for most common 1D and 2D array types.
  *
  * The general patterns are the following:
  *
  * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size,
  * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd
  * for complex double.
  *
  * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats.
  *
  * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is
  * a fixed-size 1D array of 4 complex floats.
  *
  * \sa class Array
  */

#define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix)   \
/** \ingroup arraytypedefs */                                    \
typedef Array<Type, Size, Size> Array##SizeSuffix##SizeSuffix##TypeSuffix;  \
/** \ingroup arraytypedefs */                                    \
typedef Array<Type, Size, 1>    Array##SizeSuffix##TypeSuffix;

#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size)         \
/** \ingroup arraytypedefs */                                    \
typedef Array<Type, Size, Dynamic> Array##Size##X##TypeSuffix;  \
/** \ingroup arraytypedefs */                                    \
typedef Array<Type, Dynamic, Size> Array##X##Size##TypeSuffix;

#define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4)

EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int,                  i)
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float,                f)
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double,               d)
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex<float>,  cf)
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex<double>, cd)


#undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES
#undef EIGEN_MAKE_ARRAY_TYPEDEFS

#undef EIGEN_MAKE_ARRAY_TYPEDEFS_LARGE

#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \
using Eigen::Matrix##SizeSuffix##TypeSuffix; \
using Eigen::Vector##SizeSuffix##TypeSuffix; \
using Eigen::RowVector##SizeSuffix##TypeSuffix;

#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \

#define EIGEN_USING_ARRAY_TYPEDEFS \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd)

特殊一点的地方在于,Array有一维数组,还有多维数组。一维数组的便利简单名称采样形如: ArrayNt,这里N为该维度中数组大小,t为系数数据类型。二维数组形如:ArrayNNt

示例

type typedef
Array<float,Dynamic,1> ArrayXf
Array<float,3,1> Array3f
Array<double,Dynamic,Dynamic> ArrayXXd
Array<double,3,3> Array33d

对数组系数的访问及操作

如Matrix中,重载的括号运算符()用来访问数组中的系数, 可以用来取值,也可以用于赋值。如代码中所看到的,还可以使用operator<<来初始化一个数组。


// array_1.cpp
#include <Eigen/Dense>
#include <iostream>

using namespace Eigen;
using namespace std;

int main()
{
  ArrayXXf  m(2,2);
  
  // assign some values coefficient by coefficient
  m(0,0) = 1.0; m(0,1) = 1.1;
  m(1,0) = 2.0; m(1,1) = m(0,1) + m(1,0);
  
  // print values to standard output
  cout << m << endl << endl;
 
  // using the comma-initializer is also allowed
  m << 2.0,3.0,
       8.0,9.0;
     
  // print values to standard output
  cout << m << endl;
}

执行结果:

$ g++   -I /usr/local/include/eigen3 array_1.cpp -o array_1
$ ./array_1 
  1 1.1
  2 3.1

2 3
8 9

加法及减法运算

Array重载了operator+, operator-,可以对2个Array进行加法或减法运算,当然这2个array得有相同的Size,可很容易理解。
还重载实现了一种计算:array + scalar。这会将标量加到每个数组元素上去。

示例程序:

// array_2.cpp
#include <Eigen/Dense>
#include <iostream>

using namespace Eigen;
using namespace std;

int main()
{
  ArrayXXf a(3,3);
  ArrayXXf b(3,3);

  a << 1,2,3,
       4,5,6,
       7,8,9;
  
  b << 1,2,3,
       1,2,3,
       1,2,3;
  cout<<"array a:" << endl << a <<endl;
  cout<<"array b:" << endl << b <<endl;    
  // array +/- array
  cout << "a + b = " << endl << a + b << endl << endl;
  
  // array - scalar
  cout << "a - 1 = " << endl << a - 1 << endl;
}

执行效果:

$ g++   -I /usr/local/include/eigen3 array_2.cpp -o array_2
$ 
$ ./array_2
array a:
1 2 3
4 5 6
7 8 9
array b:
1 2 3
1 2 3
1 2 3
a + b = 
 2  4  6
 5  7  9
 8 10 12

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

乘法运算

乘法分为两种: array * scalar、 array * array。其中 array * scalar与matrix一样;array * array是面向数组系数的操作,对应匹配的系数进行相乘,只有2个具有相同维度的数组才能相乘。

//array_multi.cpp

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

using namespace Eigen;
using namespace std;

int main()
{
  ArrayXXf a(2,2);
  ArrayXXf b(2,2);

  a << 1,2,
       3,4;
  b << 5,6,
       7,8;
  
  cout<<"array a:" << endl << a <<endl;
  cout<<"array b:" << endl << b <<endl;    
  
  cout << "a * b = " << endl << a * b << endl;

  cout<< "a * 2 = " << endl << a * 2 << endl;

}

执行:


$ g++   -I /usr/local/include/eigen3 array_multi.cpp -o array_multi
$
$ ./array_multi 
array a:
1 2
3 4
array b:
5 6
7 8
a * b = 
 5 12
21 32
a * 2 = 
2 4
6 8

其他的面向系数的计算

针对array,除了上面提到的 +, -, *的计算,这些都是面向数组系数的,还有其他的一些函数操作。比如abs(), sqrt(), min(.)

//array_others.cpp

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

using namespace Eigen;
using namespace std;

int main()
{
  ArrayXf a = ArrayXf::Random(5);
  a *= 2;
  cout << "a =" << endl 
       << a << endl;

  cout << "a.abs() =" << endl 
       << a.abs() << endl;

  cout << "a.abs().sqrt() =" << endl 
       << a.abs().sqrt() << endl;
       
  cout << "a.min(a.abs().sqrt()) =" << endl 
       << a.min(a.abs().sqrt()) << endl;
}

执行:

$ g++   -I /usr/local/include/eigen3 array_others.cpp -o array_other
$ 
$ ./array_other 
a =
 -1.99997
 -1.47385
  1.02242
-0.165399
 0.131069
a.abs() =
 1.99997
 1.47385
 1.02242
0.165399
0.131069
a.abs().sqrt() =
  1.4142
 1.21402
 1.01115
0.406693
0.362034
a.min(a.abs().sqrt()) =
 -1.99997
 -1.47385
  1.01115
-0.165399
 0.131069

在Array与Matrix直接转换

在Eigen内,Matrix用于线性代理计算;而Array用于针对系数进行操作,它们有不同的目的。
Matrix类表达式expression 提供了.array()函数方法,用于将矩阵matrix转换成array expression,然后就可以很容易对系数进行各种操作。对应地,Array也提供了.matrix(),用于从Array得到一个matrix expression表达式
.array(),.matrix()既可以用于右值、也可以用于左值。但在一个表达式内,混合.array(),.matrix()是不可以的。比如,你不能直接让一个矩阵matrix和数组array相加。但可以通过.array(),.matrix()进行一下转换,再进行计算。

因为经常有这样的计算需求,Eigen中Matrix提供了一个便利函数cwiseProduct(Matrix),用于处理Matrix.array() * Matrix.array()计算。

示例:

//array_matrix_1.cpp

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

using namespace Eigen;
using namespace std;

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

  m << 1,2,
       3,4;
  n << 5,6,
       7,8;
  
  cout<<"array m:" << endl << m <<endl;
  cout<<"array n:" << endl << n <<endl<<"-----------------"<< endl;
  
  result = m * n;
  cout << "-- Matrix m*n: --" << endl << result << endl << endl;
  
  result = m.array() * n.array();
  cout << "-- Array m*n: --" << endl << result << endl << endl;
  
  result = m.cwiseProduct(n);
  cout << "-- With cwiseProduct: --" << endl << result << endl << endl;
  
  result = m.array() + 4;
  cout << "-- Array m + 4: --" << endl << result << endl << endl;
}

执行一下,检查结果:

$ g++   -I /usr/local/include/eigen3 array_matrix_1.cpp -o array_matrix_1
$
$ ./array_matrix_1 
array m:
1 2
3 4
array n:
5 6
7 8
-----------------
-- 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!