在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 是直接对矩阵进行整形,矩阵Matrix立即改变。
MatrixXi m = Matrix4i::Random ();
m.resize(2,8); //执行这个指令后m就改变了
注:resize取决于输入的存储顺序,Eigen中一般按行存储,但可以设置
Map类的作用:有时候已经创建了一个数组,此时想把它当成一个矩阵或者向量,当然你可以直接创建一个与其一摸一样的矩阵,但这样原来的数组和新建的矩阵都在内存上,都占用了空间。为此有了Map类,它将已经存在的数组”解释成(映射成)“矩阵,实际上就是给数组取了一个”矩阵别名“。
template
class Eigen::Map< PlainObjectType, MapOptions, StrideType >
参数 | 意义 |
---|---|
PlainObjectType |
所要映射的矩阵类型 |
MapOptions |
指定指针的对齐方式,默认为Unaligned ,就是内存按多少位一个解释 |
`StrideType | 类对象,表明行列的递增值(指针的递增值) |
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}
的数组,对其映射是:
MatrixXi
;不指定指针对其方式,0
;array
;矩阵行列3x3;Stride(8, 2)
表明,每一列相比于第一列指针数每次增加8;每一行相对于第一行指针书增加2。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()
。
a.noalias()
来指明。.eval
和.xxxInPlace()
来避免混叠。