Eigen3学习笔记——密集矩阵和数组操作(3)

矩阵重新整形

reshape

3.4 以后reshape不执行立即整形,而是返回一个**”view“**(意思应该是不在是具体的矩阵,而是一种简化)

因此,不允许整形之后直接赋值:A = A.reshap(2,8),可以进行A = A.reshap(2,8).eval(),**eval()**是将表达式转换成矩阵!!

DenseBase::reshape(NRowsType,NColsType); 		//将矩阵重新按行和列进行排序
DenseBase::reshape()							//将矩阵按列排列

Matrix4i m = Matrix4i::Random ();
m.reshape(2, 8);						//将一个4x4矩阵重新排列为2x8矩阵,行优先排列
m.reshape();							//将矩阵按列重新排序

resize

resize 是直接对矩阵进行整形,矩阵Matrix立即改变。

MatrixXi m = Matrix4i::Random ();
m.resize(2,8);							//执行这个指令后m就改变了

注:resize取决于输入的存储顺序,Eigen中一般按行存储,但可以设置

STL迭代器和算法(先略去)

Map类

Map类的作用:有时候已经创建了一个数组,此时想把它当成一个矩阵或者向量,当然你可以直接创建一个与其一摸一样的矩阵,但这样原来的数组和新建的矩阵都在内存上,都占用了空间。为此有了Map类,它将已经存在的数组”解释成(映射成)“矩阵,实际上就是给数组取了一个”矩阵别名“

Map的类模板部分

template
class Eigen::Map< PlainObjectType, MapOptions, StrideType >
参数 意义
PlainObjectType 所要映射的矩阵类型
MapOptions 指定指针的对齐方式,默认为Unaligned,就是内存按多少位一个解释
`StrideType 类对象,表明行列的递增值(指针的递增值)

Map的构造函数部分

Map对象没有默认构造函数,必须用参数进行构造,他就一别名,不新开内存

Map(PointerArgType dataPtr, const StrideType& stride = StrideType());	
Map(PointerArgType dataPtr, Index size, const StrideType& stride = StrideType());
Map(PointerArgType dataPtr, Index rows, Index cols,const StrideType& stride = StrideType());
参数 意义
dataPtr 所要引用的内存的首地址,就是数组名字
size 新映射的矩阵大小
rows 新映射的矩阵行数
cols 新映射的矩阵列数
stride 新映射的时候行列指针增长方式
int array[24];
for(int i = 0; i < 24; ++i) array[i] = i;
cout << Map>
		(array, 3, 3, Stride(8, 2))
		<< endl;
//输出为:
//0  8 16
//2 10 18
//4 12 20

**解释:**原本array[24]是一个{0,1,2...,23}的数组,对其映射是:

  1. 动态矩阵,MatrixXi;不指定指针对其方式,0
  2. 内存地址为array;矩阵行列3x3;
  3. Stride(8, 2)表明,每一列相比于第一列指针数每次增加8;每一行相对于第一行指针书增加2。
  4. Stride:这两个值可以在编译时作为模板参数传递,也可以在运行时作为构造函数的参数传递。

注意:Eigen中的Matrix类型也可以进行相应操作,只不过要取地址

而且,Eigen中的函数都被编写成可以接受Map对象,真就是别名呗

更映射数组

可以通过new来对声明后的Map对象数组进行更改

//官方文件代码
int data[] = {1,2,3,4,5,6,7,8,9};
Map v(data,4);
cout << "映射的向量 v 是:" << v << "\n" ;
new (&v) Map(data+4,5);
cout << "现在 v 是:" << v << "\n" ;

这不就是重新在堆上开辟了一个区域么,只不过Map对象v代表的内存位置变了而已。不过这个new后跟的参数很奇特。

矩阵混叠现象

这里解释之前出现的Aliasing issue。这种现象的产生是由于Eigen中使用的是一种lazy evaluation,不是分配好内存后赋值,而是在原有的内存上进行操作

现象如下:

MatrixXi mat(3,3); 
mat << 1, 2, 3,   4, 5, 6,   7, 8, 9;
mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
/*
mat为变换前
1 2 3
4 5 6
7 8 9
期望是:
1 2 3
4 1 2
7 4 5
实际上mat变换后
1 2 3
4 1 2
7 4 1
这是因为,Eigen中执行的是:
mat(1,1) = mat(0,0);
mat(1,2) = mat(0,1);
mat(2,1) = mat(1,0);
mat(2,2) = mat(1,1);
*/

解决混叠问题

解决的方法就是将右边的矩阵直接进行是现成临时矩阵,然后在赋值。使用到的函数就是.eval()

mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2).eval();
//修改代码后就能完成之前期望的操作

我自己的理解:在Eigen中,有的函数操作矩阵后不会立即改变矩阵,而只是记录这种改变,等到真的要进行赋值时才进行操作,比如:a.trasnpose();而另一种函数操作矩阵后会立即改变矩阵的,比如:a.transposeInPlace()。两种方法的使用取决于你想不想改变a。如果想改变a那么推荐使用a.transposeInPlace()而不是a.transposeInPlace().eval(),因为Eigen对前者优化更好。Eigen中有很多类似的xxxInPlace()

混叠问题的总结

  1. 混叠对元素计算是无害的;这包括标量乘法和矩阵或数组加法,从位置的对应关系上看,没有混叠。
  2. 当将两个矩阵相乘时,Eigen 直接假设有混叠,并会创建中间变量来避免混叠,这将降低效率。因此,如果知道没有混叠,那么使用a.noalias()来指明。
  3. Eigen 对于其他操作假设没有混叠,此时需要用.eval.xxxInPlace()来避免混叠。

你可能感兴趣的:(线性代数,c++)