1.2 eigen中矩陣和向量的運算


 

1.2 矩陣和向量的運算

 

1.介紹

eigen給矩陣和向量的算術運算提供重載的c++算術運算符例如+-*或這一些點乘dot(),叉乘cross()等等。對於矩陣類(矩陣和向量,之后統稱為矩陣

類),算術運算只重載線性代數的運算。例如matrix1*matrix2表示矩陣的乘法,同時向量+標量是不允許的!如果你想進行所有的數組算術運算,請看下

一節!

2.加減法

因為eigen庫無法自動進行類型轉換,因此矩陣類的加減法必須是兩個同類型同維度的矩陣類相加減。

這些運算有:

雙目運算符:+a+b

雙目運算符:-a-b

單目運算符:--a

復合運算符:+=a+=b

復合運算符:-=a-=b

例子:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
Matrix2d a;
a << 1, 2,
3, 4;
MatrixXd b(2,2);
b << 2, 3,
1, 4;
std::cout << "a + b =\n" << a + b << std::endl;
std::cout << "a - b =\n" << a - b << std::endl;
std::cout << "Doing a += b;" << std::endl;
a += b;
std::cout << "Now a =\n" << a << std::endl;
Vector3d v(1,2,3);
Vector3d w(1,0,0);
std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
} 

3.標量乘法和除法

標量的乘除法非常簡單:

雙目運算符:*matrix*scalar

雙目運算符:*scalar*matrix

即乘法滿足交換律

雙目運算符:/matrix/scalar

矩陣中的每一個元素除以標量

復合運算符:*=matrix*=scalar

復合運算符:/=matrix/=scalar

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
Matrix2d a;
a << 1, 2,
3, 4;
Vector3d v(1,2,3);
std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;
std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;
std::cout << "Doing v *= 2;" << std::endl;
v *= 2;
std::cout << "Now v =\n" << v << std::endl;
}
//output
a * 2.5 =
2.5 5
7.5 10
0.1 * v =
0.1
0.2
0.3
Doing v *= 2;
Now v =
2
4
6

 

4.對表達式模板的注釋

 在eigen中,+號算術運算符不會通過自身函數執行任何計算,它們只是返回一個表達式,來描述計算的過程。實際的計算是在執行等號時,整個表達式開

始進行計算。

 比如:

VectorXf a(50), b(50), c(50), d(50);
...
a = 3*b + 4*c + 5*d;

eigen把它編譯成一個循環,這樣數組只執行依次運算,就像下列循環一樣:

for(int i = 0; i < 50; ++i)
a[i] = 3*b[i] + 4*c[i] + 5*d[i]; 

因此,在eigen 中,你不必擔心使用相當大的算術運算表達式,它會提供給eigen更多優化代碼的機會。

5.轉置和共軛

矩陣類的成員函數transpose(),conjugate(),adjoint(),分別對應矩陣的轉置 ,共軛 ,共軛轉置矩陣特此說明adjoint()並不表示伴隨矩

陣,而是共軛轉置矩陣!!!!

例子:

MatrixXcf a = MatrixXcf::Random(2,2);//生成隨機的復數類型矩陣
cout << "Here is the matrix a\n" << a << endl;
cout << "Here is the matrix a^T\n" << a.transpose() << endl;
cout << "Here is the conjugate of a\n" << a.conjugate() << endl;
cout << "Here is the matrix a^*\n" << a.adjoint() << endl;
//output
Here is the matrix a
(-0.211,0.68) (-0.605,0.823)
(0.597,0.566) (0.536,-0.33)
Here is the matrix a^T
(-0.211,0.68) (0.597,0.566)
(-0.605,0.823) (0.536,-0.33)
Here is the conjugate of a
(-0.211,-0.68) (-0.605,-0.823)
(0.597,-0.566) (0.536,0.33)
Here is the matrix a^*
(-0.211,-0.68) (0.597,-0.566)
(-0.605,-0.823) (0.536,0.33)

對於實矩陣,是沒有共軛矩陣的,同時它的共軛轉置矩陣(adjoint())等於它的轉置(transpose()).

對於基本的算術運算,轉置和共軛轉置函數返回的是矩陣的引用,而不會實際轉換矩陣對象。如果你對bb=a.transpose(),這個將在求轉置矩陣的同時,

將結果賦值給b。但是如果將a=a.transpose(),eigen將會在計算a的轉置完成之前開始賦值結果給a,因此,這樣的賦值將不會將a替換成它的轉置,而是:

Matrix2i a; a << 1, 2, 3, 4;
cout << "Here is the matrix a:\n" << a << endl;
a = a.transpose(); // !!! do NOT do this !!!

cout << "and the result of the aliasing effect:\n" << a << endl;
//output
Here is the matrix a:
1 2
3 4
and the result of the aliasing effect:
1 2
2 4

 結果不再是a的轉置,而是發生了混疊(aliasing issue.在調試模式中,在到達斷點之前,這樣的錯誤很容易被檢測到。

為了將a替換為a的轉置矩陣,可以使用transposeInPlace()函數:

MatrixXf a(2,3); a << 1, 2, 3, 4, 5, 6;
cout << "Here is the initial matrix a:\n" << a << endl;
a.transposeInPlace();
cout << "and after being transposed:\n" << a << endl;
//output
Here is the initial matrix a:
1 2 3
4 5 6
and after being transposed:
1 4
2 5
3 6

同樣地,對於共軛轉置矩陣(adjoint())也有類似的成員函數(adjointInPlace()).

6.矩陣-矩陣乘法和矩陣-向量乘法

矩陣乘法使用*運算符;

雙目運算符:a*b

復合運算符:a*=b

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
Matrix2d mat;
mat << 1, 2,
3, 4;
Vector2d u(-1,1), v(2,0);
std::cout << "Here is mat*mat:\n" << mat*mat << std::endl;
std::cout << "Here is mat*u:\n" << mat*u << std::endl;
std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;
std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;
std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;
std::cout << "Let's multiply mat by itself" << std::endl;
mat = mat*mat;
std::cout << "Now mat is mat:\n" << mat << std::endl;
}
//output
Here is mat*mat:
7 10
15 22
Here is mat*u:
1
1
Here is u^T*mat:
2 2
Here is u^T*v:
-2
Here is u*v^T:
-2 -0
2 0
Let's multiply mat by itself
Now mat is mat:
7 10
15 22

說明,前述表達式m=m*m可能會引起混疊的問題,但是對於矩陣乘法而言,不必擔心:eigen將矩陣的乘法看作一種特殊的情況,它引入一個臨時變量,

因此它將編譯成以下代碼:

tmp = m*m;
m = tmp;

如果你想讓矩陣乘法安全的進行計算而沒有混疊問題,你可以使用noalias()成員函數來避免臨時變量的問題,例如:

c.noalias() += a * b; 

7.點乘和叉乘

點乘dot(),叉乘cross().點乘也可以使用u.adjoint()*v

例子:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main()
{
Vector3d v(1,2,3);
Vector3d w(0,1,2);
cout << "Dot product: " << v.dot(w) << endl;//點乘
double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
cout << "Dot product via a matrix product: " << dp << endl;
cout << "Cross product:\n" << v.cross(w) << endl;//叉乘
}
//output
Dot product: 8
Dot product via a matrix product: 8
Cross product:
1
-2
1 

注意:叉乘只能用於維數為3的向量,點乘使用於任何維數的向量。當使用復數時,第一個變量是共軛線性運算,第二個是線性運算。

8.基本的算術化簡計算

eigen提供一些簡化計算將給定的矩陣或向量編程單個值,比如對矩陣的所有元素求和sum(),求積prod(),求最大值maxCoeff()和求最小值

minCoeff()

#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl;//對矩陣所有元素求和
cout << "Here is mat.prod(): " << mat.prod() << endl;//對矩陣所有元素求積
cout << "Here is mat.mean(): " << mat.mean() << endl;//對矩陣所有元素求平均值
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;//取矩陣的元素最小值
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;//取矩陣元素的最大值
cout << "Here is mat.trace(): " << mat.trace() << endl;//取矩陣元素的跡
}
//output
Here is mat.sum(): 10
Here is mat.prod(): 24
Here is mat.mean(): 2.5
Here is mat.minCoeff(): 1
Here is mat.maxCoeff(): 4
Here is mat.trace(): 5

矩陣的跡返回的是矩陣對角線元素的和,等價於a.diagonal().sum().

同時求最大值和最小值的函數可以接受引用的實參,來表示其最大最小值的行數和列數:

Matrix3f m = Matrix3f::Random();
std::ptrdiff_t i, j;//i,j是一個整型類型
float minOfM = m.minCoeff(&i,&j);//矩陣可以接受兩個引用參數
cout << "Here is the matrix m:\n" << m << endl;
cout << "Its minimum coefficient (" << minOfM << ") is at position (" << i << "," << j << ")\n\n";//輸出最小值所在行數列數
RowVector4i v = RowVector4i::Random();
int maxOfV = v.maxCoeff(&i);//向量只接受一個引用參數
cout << "Here is the vector v: " << v << endl;
cout << "Its maximum coefficient (" << maxOfV << ") is at position " << i << endl;//輸出最大值所在列數
//output
Here is the matrix m:
0.68 0.597 -0.33
-0.211 0.823 0.536
0.566 -0.605 -0.444
Its minimum coefficient (-0.605) is at position (2,1)
Here is the vector v: 1 0 3 -3
Its maximum coefficient (3) is at position 2

9.運算的有效性

eigen庫會檢查你定義的運算。通常它在編譯時檢查並產生錯誤信息。這些錯誤信息可能很長很丑,但是eigen將重要信息用大寫字母來顯示出,例如:

Matrix3f m;
Vector4f v;
v = m*v; // Compile-time error: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES

在許多情況下,當使用動態綁定矩陣時,編譯器將不會在編譯時檢查,eigen將會在運行時檢查,yejiuis說程序有可能因為不合法的運算而中斷。

MatrixXf m(3,3);
VectorXf v(4);
v = m * v; // Run-time assertion failure here: "invalid matrix product"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM