Eigen介紹
Eigen是可以用來(lái)進(jìn)行線性代數(shù)、矩陣祟偷、向量操作等運(yùn)算的C++庫(kù)察滑,它里面包含了很多算法。它的License是MPL2修肠。它支持多平臺(tái)贺辰。使用類(lèi)似Matlab的方式操作矩陣,單純講和Matlab的對(duì)應(yīng)的話,可能不如Armadillo(http://arma.sourceforge.net/)對(duì)應(yīng)的好饲化,但功能絕對(duì)強(qiáng)大莽鸭。
Eigen包含了絕大部分你能用到的矩陣算法,同時(shí)提供許多第三方的接口吃靠。Eigen一個(gè)重要特點(diǎn)是采用源碼的方式提供給用戶使用蒋川,在使用時(shí)只需要包含Eigen的頭文件即可進(jìn)行使用。之所以采用這種方式撩笆,是因?yàn)镋igen采用模板方式實(shí)現(xiàn)捺球,由于模板函數(shù)不支持分離編譯,所以只能提供源碼而不是動(dòng)態(tài)庫(kù)的方式供用戶使用夕冲,因此非常輕量而易于跨平臺(tái)氮兵。你要做的就是把用到的頭文件和你的代碼放在一起就可以了。
Eigen的一些特性:
- 支持整數(shù)歹鱼、浮點(diǎn)數(shù)泣栈、復(fù)數(shù),使用模板編程弥姻,可以為特殊的數(shù)據(jù)結(jié)構(gòu)提供矩陣操作南片。比如在用ceres-solver進(jìn)行做優(yōu)化問(wèn)題(比如bundle adjustment)的時(shí)候,有時(shí)候需要用模板編程寫(xiě)一個(gè)目標(biāo)函數(shù)庭敦,ceres可以將模板自動(dòng)替換為內(nèi)部的一個(gè)可以自動(dòng)求微分的特殊的double類(lèi)型疼进。而如果要在這個(gè)模板函數(shù)中進(jìn)行矩陣計(jì)算,使用Eigen就會(huì)非常方便秧廉。
- 支持逐元素伞广、分塊、和整體的矩陣操作疼电。
- 內(nèi)含大量矩陣分解算法包括LU嚼锄,LDLt,QR蔽豺、SVD等等区丑。
- 支持使用Intel MKL加速
- 部分功能支持多線程
- 稀疏矩陣支持良好,到今年新出的Eigen3.3修陡,已經(jīng)自帶了SparseLU沧侥、SparseQR、共軛梯度(ConjugateGradient solver)濒析、bi conjugate gradient stabilized solver等解稀疏矩陣的功能正什。同時(shí)提供SPQR啥纸、UmfPack等外部稀疏矩陣庫(kù)的接口号杏。
- 支持常用幾何運(yùn)算,包括旋轉(zhuǎn)矩陣、四元數(shù)盾致、矩陣變換主经、AngleAxis(歐拉角與Rodrigues變換)等等。
- 更新活躍庭惜,用戶眾多(Google罩驻、WilliowGarage也在用),使用Eigen的比較著名的開(kāi)源項(xiàng)目有ROS(機(jī)器人操作系統(tǒng))护赊、PCL(點(diǎn)云處理庫(kù))惠遏、Google Ceres(優(yōu)化算法)。OpenCV自帶到Eigen的接口骏啰。
總體來(lái)講节吮,如果經(jīng)常做一些比較復(fù)雜的矩陣計(jì)算的話,或者想要跨平臺(tái)的話判耕,非常值得一用透绩。
Eigen是C++中可以用來(lái)調(diào)用并進(jìn)行矩陣計(jì)算的一個(gè)庫(kù),里面封裝了一些類(lèi)壁熄,需要的頭文件和功能如下:
Eigen的主頁(yè)上有一些更詳細(xì)的Eigen介紹帚豪。
Eigen的下載
這里是官網(wǎng)主頁(yè),可自行下載需要的版本草丧,是個(gè)code包狸臣,不用安裝。
Eigen的配置
這里以VS2015為例昌执,C/C++ -> Additional Include Directories填上Eigen解壓文件夾的位置即可固棚,也可將文件夾放在Solution目錄下,寫(xiě)作:$(SolutionDir)\eigen3
Eigen:矩陣(Matrix)類(lèi)的介紹及使用
在Eigen中仙蚜,所有矩陣和向量均為Matrix模板類(lèi)的對(duì)象此洲,向量是矩陣的行(或列)為1是的特殊情況。
1委粉、矩陣的三參數(shù)模板
Matrix類(lèi)有六個(gè)模板參數(shù)呜师,其中三個(gè)有默認(rèn)值,因此只要學(xué)習(xí)三個(gè)參數(shù)就足夠了贾节。
/* 強(qiáng)制性的三參數(shù)模板的原型 (三個(gè)參數(shù)分別表示:標(biāo)量的類(lèi)型汁汗,編譯時(shí)的行,編譯時(shí)的列) */
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
/* 用typedef定義了很多模板栗涂,例如:Matrix4f 表示 4×4 的floats 矩陣 */
typedef Matrix<float, 4, 4> Matrix4f;
2知牌、向量(Vectors)
向量是矩陣的特殊情況,也是用矩陣定義的斤程。
typedef Matrix<float, 3, 1> Vector3f;
typedef Matrix<int, 1, 2> RowVector2i;
3角寸、特殊動(dòng)態(tài)值(special value Dynamic)
Eigen的矩陣不僅能夠在編譯是確定大衅谢臁(fixed size),也可以在運(yùn)行時(shí)確定大小扁藕,就是所說(shuō)的動(dòng)態(tài)矩陣(dynamic size)沮峡。
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
/* 也可使用‘行’固定‘列’動(dòng)態(tài)的矩陣 */
Matrix<float, 3, Dynamic>
4、構(gòu)造函數(shù)(Constructors)
可以使用默認(rèn)的構(gòu)造函數(shù)亿柑,不執(zhí)行動(dòng)態(tài)分配內(nèi)存邢疙,也沒(méi)有初始化矩陣參數(shù):
Matrix3f a; // a是3-by-3矩陣,包含未初始化的 float[9] 數(shù)組
MatrixXf b; // b是動(dòng)態(tài)矩陣望薄,當(dāng)前大小為 0-by-0, 沒(méi)有為數(shù)組的系數(shù)分配內(nèi)存
/* 矩陣的第一個(gè)參數(shù)表示“行”疟游,數(shù)組只有一個(gè)參數(shù)。根據(jù)跟定的大小分配內(nèi)存痕支,但不初始化 */
MatrixXf a(10,15); // a 是10-by-15陣乡摹,分配了內(nèi)存,沒(méi)有初始化
VectorXf b(30); // b是動(dòng)態(tài)矩陣采转,當(dāng)前大小為 30, 分配了內(nèi)存聪廉,沒(méi)有初始化
/* 對(duì)于給定的矩陣,傳遞的參數(shù)無(wú)效 */
Matrix3f a(3,3);
/* 對(duì)于維數(shù)最大為4的向量故慈,可以直接初始化 */
Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);
5板熊、系數(shù)訪問(wèn)
系數(shù)都是從0開(kāi)始,矩陣默認(rèn)按列存儲(chǔ)
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = m(1, 0) + m(0, 1);
cout << "Here is the matrix m:" << endl;
cout << m << endl;
VectorXd v(2);
v(0) = 4;
v[1] = v[0] - 1; //operator[] 在 vectors 中重載察绷,意義和()相同
cout << "Here is the vector v:" << endl;
cout << v << endl;
getchar();
getchar();
}
6干签、逗號(hào)分隔的初始化
Matrix3f m;
m << 1, 2, 3, 4, 5, 6, 7, 8, 9;
cout << m;
7、Resizing
可以用rows(), cols() and size() 改變現(xiàn)有矩陣的大小拆撼。這些類(lèi)方法返回行容劳、列、系數(shù)的數(shù)值闸度。也可以用resize()來(lái)改變動(dòng)態(tài)矩陣的大小竭贩。
test代碼
#include <iostream>
#include "Eigen/Eigen"
using namespace std;
using namespace Eigen;
void foo(MatrixXf& m)
{
Matrix3f m2=Matrix3f::Zero(3,3);
m2(0,0)=1;
m=m2;
}
int main()
{
/* 定義,定義時(shí)默認(rèn)沒(méi)有初始化莺禁,必須自己初始化 */
MatrixXf m1(3,4); //動(dòng)態(tài)矩陣留量,建立3行4列。
MatrixXf m2(4,3); //4行3列哟冬,依此類(lèi)推楼熄。
MatrixXf m3(3,3);
Vector3f v1; //若是靜態(tài)數(shù)組,則不用指定行或者列
/* 初始化 */
m1 = MatrixXf::Zero(3,4); //用0矩陣初始化,要指定行列數(shù)
m2 = MatrixXf::Zero(4,3);
m3 = MatrixXf::Identity(3,3); //用單位矩陣初始化
v1 = Vector3f::Zero(); //同理浩峡,若是靜態(tài)的可岂,不用指定行列數(shù)
m1 << 1,0,0,1, //也可以以這種方式初始化
1,5,0,1,
0,0,9,1;
m2 << 1,0,0,
0,4,0,
0,0,7,
1,1,1;
/* 元素的訪問(wèn) */
v1[1] = 1;
m3(2,2) = 7;
cout<<"v1:\n"<<v1<<endl;
cout<<"m3:\n"<<m3<<endl;
/* 復(fù)制操作 */
VectorXf v2=v1; //復(fù)制后,行數(shù)與列數(shù)和右邊的v1相等,matrix也是一樣,
//也可以通過(guò)這種方式重置動(dòng)態(tài)數(shù)組的行數(shù)與列數(shù)
cout<<"v2:\n"<<v2<<endl;
/* 矩陣操作翰灾,可以實(shí)現(xiàn) + - * / 操作缕粹,同樣可以實(shí)現(xiàn)連續(xù)操作(但是維數(shù)必須符合情況),
如m1,m2,m3維數(shù)相同,則可以m1 = m2 + m3 + m1; */
m3 = m1 * m2;
v2 += v1;
cout<<"m3:\n"<<m3<<endl;
cout<<"v2:\n"<<v2<<endl;
//m3 = m3.transpose(); 這句出現(xiàn)錯(cuò)誤稚茅,估計(jì)不能給自己賦值
cout<<"m3轉(zhuǎn)置:\n"<<m3.transpose()<<endl;
cout<<"m3行列式:\n"<<m3.determinant()<<endl;
m3 = m3.inverse();
cout<<"m3求逆:\n"<<m3<<endl;
system("pause");
return 0;
}
本文同時(shí)發(fā)布在個(gè)人主頁(yè)fangda.me上。