亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++中線性代數(shù)計(jì)算Eigen庫(kù)的使用教程詳解

 更新時(shí)間:2023年12月30日 09:23:38   作者:yuanhao  
Eigen是一個(gè)基于線性代數(shù)的C++模板庫(kù),主要用于矩陣、向量、數(shù)值求解和相關(guān)算法,本文主要為大家簡(jiǎn)單聊聊Eigen庫(kù)的使用,希望對(duì)大家有所幫助

前言

Eigen是一個(gè)基于線性代數(shù)的C++模板庫(kù),主要用于矩陣、向量、數(shù)值求解和相關(guān)算法。Eigen庫(kù)有如下特點(diǎn):

  • 支持整數(shù)、浮點(diǎn)數(shù)、復(fù)數(shù),使用模板編程,可以為特殊的數(shù)據(jù)結(jié)構(gòu)提供矩陣操作;
  • Open-CV自帶Eigen的接口;
  • 支持逐元素、分塊和整體的矩陣操作。
  • 支持使用Intel MKL加速部分功能。
  • 支持多線程,對(duì)稀疏矩陣支持良好。
  • 支持常用幾何運(yùn)算,包括旋轉(zhuǎn)矩陣、矩陣變換等。

所以不論是做算法還是C++開發(fā),使用好Eigen庫(kù)會(huì)讓你事半功倍。

由于本人是非專業(yè)的算法工程師,所以這里也只是做一些簡(jiǎn)單入門介紹和使用。

類型定義

Eigen庫(kù)中的核心類就是Matrix,它表示矩陣,是一個(gè)模板類,定義如下:

template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
class Matrix {
    
}

其中前3個(gè)模板參數(shù)需要我們指定,后面3個(gè)參數(shù)使用默認(rèn)即可。

第一個(gè)參數(shù)typename _Scalar,表示該參數(shù)是一個(gè)數(shù)據(jù)類型,而不是像_Rows_Cols這樣的變量。那么現(xiàn)在比如我想定義一個(gè)4x4float矩陣,就可以如下定義:

Matrix<float,4,4> matrix44f;

這樣定義雖然簡(jiǎn)單明了,但是有點(diǎn)長(zhǎng),所以在Eigen庫(kù)中提供了很多開源直接使用的模板類,比如:

  • Matrix4f,表示4x4float矩陣;
  • Vector3f,表示列向量,長(zhǎng)度3的float向量;
  • RowVector2i,表示行向量,長(zhǎng)度2的int向量;

所以對(duì)于一些常見矩陣可以使用內(nèi)置的模板類。

除了定義已知大小的矩陣,Eigen庫(kù)還可以定義動(dòng)態(tài)矩陣。那什么是動(dòng)態(tài)矩陣和靜態(tài)矩陣呢?

靜態(tài)矩陣就是編譯時(shí)候就知道大小的矩陣,比如Matrix3d,在編譯時(shí)我們就知道這是一個(gè)3x3double類型矩陣。

與之對(duì)應(yīng)的是動(dòng)態(tài)矩陣,這種矩陣需要在運(yùn)行后才知道大小,比如需要從vector<vector<double>>數(shù)據(jù)類型中構(gòu)建矩陣,只有當(dāng)代碼運(yùn)行時(shí)才可以知道構(gòu)建的矩陣的行列個(gè)數(shù)。這時(shí)可以使用MatrixXd來表示任意大小的元素類型為double的矩陣變量,其中X就表示未知大小,即Dynamic動(dòng)態(tài)的意思。

對(duì)于矩陣類型后面的后綴表示元素類型,Eigen庫(kù)定義了4種元素類型:

  • d:表示double類型;
  • f:表示float類型;
  • i:表示整數(shù);
  • c:表示復(fù)數(shù);

比如Matrix2c,表示一個(gè)2x2元素類型為復(fù)數(shù)的矩陣。

新建矩陣

對(duì)于默認(rèn)構(gòu)造函數(shù)的矩陣,分配了大小和內(nèi)存空間,但是沒有初始化矩陣元素。而對(duì)于基本數(shù)據(jù)類型,默認(rèn)初始化的話,其值是隨機(jī)的,不能使用。比如下面代碼:

    Eigen::Matrix2f m;
    std::cout << "m:" << std::endl << m << std::endl;
    Eigen::Vector4i n;
    std::cout << "n:" << std::endl << n << std::endl;
?
//運(yùn)行結(jié)果:
m:
5.88604e-039            0
9.18341e-041  2.8026e-045
n:
-517829874
        -2
1952350234
   4199631

在Eigen中重載了std::cout<<運(yùn)算符,所以可以直接使用std::cout打印矩陣結(jié)果。所以定義完矩陣后,我們必須要對(duì)進(jìn)行初始化。對(duì)于矩陣的初始化,有如下幾種方式: 0. 直接賦值,可以使用<<進(jìn)行賦值。

    Eigen::Matrix2f m;  //2x2的float矩陣
    m << 1.9,2.884,     //進(jìn)行初始化,期望是4個(gè)值
         4.33,5.898;
    std::cout << "m:" << std::endl << m << std::endl;
?
    Eigen::Vector4i n;  //長(zhǎng)度為4的列向量
    n << 3,4,2,6;
    std::cout << "n:" << std::endl << n << std::endl;
?
//運(yùn)行結(jié)果:
m:
  1.9 2.884
 4.33 5.898
n:
3
4
2
6

這種方式只適合于矩陣的大小固定的情況,這種初始化方式很像使用列表初始化的數(shù)組,只有知道矩陣的大小,其構(gòu)造函數(shù)才能從左向右、從上向下來進(jìn)行初始化。比如可以定義動(dòng)態(tài)大小的矩陣MatrixXd,這時(shí)就無法使用<<進(jìn)行直接賦值,比如:

    Eigen::MatrixXi xi;     //動(dòng)態(tài)大小的int矩陣
    xi << 1,2,3,4,5,6;
    std::cout << "xi:" << std::endl << xi << std::endl;

因?yàn)檫@種定義的變量xi,并不知道其行列數(shù)目,可能是3x2、2x3等等,所以用6個(gè)int去賦值,構(gòu)造函數(shù)無法進(jìn)行構(gòu)造。

對(duì)于向量,可以在構(gòu)造的時(shí)候進(jìn)行初始化。

    Eigen::RowVector3d k(1,2,3);    //長(zhǎng)度為3,類型為double的行向量
     std::cout << "k:" << std::endl << k << std::endl;

一些特殊函數(shù),比如全部初始化為0,初始化為1,隨機(jī)數(shù)等。

Eigen::MatrixXi zero = MatrixXi::Zero(3,4);    //全部初始化為0的矩陣
std::cout << "------ zero ------" << std::endl << zero << std::endl;
Eigen::MatrixXi one = MatrixXi::Ones(4,4);      //全部初始化為1的矩陣
std::cout << "------ one ------" << std::endl << one << std::endl;
Eigen::MatrixXi i = MatrixXi::Identity(3,3);    //單位矩陣
std::cout << "------ i ------" << std::endl << i << std::endl;
Eigen::Matrix4f random = Matrix4f::Random();    //隨機(jī)矩陣
std::cout << "------ random ------" << std::endl << random << std::endl;

運(yùn)行結(jié)果:

------ zero ------
0 0 0 0
0 0 0 0
0 0 0 0
------ one ------
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
------ i ------
1 0 0
0 1 0
0 0 1
------ random ------
 -0.997497   0.170019    0.64568   0.421003
  0.127171 -0.0402539    0.49321  0.0270699
 -0.613392  -0.299417  -0.651784   -0.39201
  0.617481   0.791925   0.717887  -0.970031
 

使用Eigen::Map已有的內(nèi)存塊數(shù)據(jù)映射到矩陣,必須要指定需要映射的矩陣類型,是MatrixXdVectorXd等等,在模板參數(shù)中指明。

看一下Eigen::Map函數(shù)的定義:

template< e> class Map
  : public MapBase<Map<PlainObjectType, MapOptions, StrideType> >
{
?
}
  • PlanObjectType:映射數(shù)據(jù)的等效矩陣類型。
  • MapOptions:指定指針對(duì)齊方式,以字節(jié)為單位,默認(rèn)為Unaligned,即未對(duì)齊。
  • StrideType:可選擇指定步幅。默認(rèn)情況下,Map采用內(nèi)存布局是一個(gè)普通的、連續(xù)的數(shù)組,可以通過指定步幅來定制化。

正常我們只需指明第一個(gè)參數(shù)即可,使用Map可以在無任何其他開銷的情況下,讓Eigen使用非Eigen數(shù)據(jù)結(jié)構(gòu)來對(duì)其進(jìn)行初始化,包括多種數(shù)據(jù)結(jié)構(gòu),比如原生數(shù)組,比如double[]、float[]等,以及STL容器,比如std::vector、std::array等。

    std::vector<double> vec = {1,2,3,4,5,6};    //std::vector數(shù)據(jù)類型
    Eigen::Map<Eigen::VectorXd> vd(vec.data(),6);   //構(gòu)造成一個(gè)長(zhǎng)度為6的列向量
    std::cout << "------ vd ------" << std::endl << vd << std::endl;
    Eigen::Map<Eigen::MatrixXd> xd(vec.data(),3,2); //構(gòu)造成一個(gè)3x2的矩陣
    std::cout << "------ xd ------" << std::endl << xd << std::endl;
    
    //運(yùn)行結(jié)果:
------ vd ------
1
2
3
4
5
6
------ xd ------
1 4
2 5
3 6

在上面代碼中,我們使用vec.data()來獲取數(shù)vector中的數(shù)組數(shù)據(jù),同時(shí)必須確定矩陣或者向量的大小。

對(duì)于矩陣來說,還有一種非常常見的初始化方式,就是一行一行或者一列一列進(jìn)行賦值。比如代碼:

Eigen::MatrixXd mat(3,2); //創(chuàng)建一個(gè)3x2的double類型矩陣
mat.col(0) << 1,2,3;    //對(duì)第一列進(jìn)行初始化
mat.col(1) << 4,5,6;    //對(duì)第二列進(jìn)行初始化

這種方式在構(gòu)建特殊矩陣時(shí)經(jīng)常用到。

矩陣索引

當(dāng)前矩陣的行數(shù)、列數(shù)和大小可以分別通過rows()、cols()size()方法來獲取,在遍歷Eigen矩陣時(shí)最好獲取行數(shù)、列數(shù)來限制范圍。

同時(shí)索引下標(biāo)從0開始,矩陣元素的訪問可以通過matrix(i,j)來訪問第i行第j列的元素,對(duì)于向量還可以使用類似數(shù)組取值的vector[i]來訪問第i個(gè)元素。比如代碼:

    std::vector<double> vec = {1,2,3,4,5,6};
    Eigen::Map<Eigen::VectorXd> vd(vec.data(),6);   //創(chuàng)建一個(gè)長(zhǎng)度為6的列向量
    std::cout << "------ vd ------" << std::endl << vd << std::endl;
    Eigen::Map<Eigen::MatrixXd> xd(vec.data(),3,2); //創(chuàng)建一個(gè)3x2的矩陣
    std::cout << "------ xd ------" << std::endl << xd << std::endl;
?
    for (int i = 0; i < xd.rows(); ++i) {
        for (int j = 0; j < xd.cols(); ++j) {
            std::cout << "xd.(" << i << "," << j << ")= " << xd(i,j) << std::endl;
        }
    }
?
    //運(yùn)行結(jié)果:
------ xd ------
1 4
2 5
3 6
xd.(0,0)= 1
xd.(0,1)= 4
xd.(1,0)= 2
xd.(1,1)= 5
xd.(2,0)= 3
xd.(2,1)= 6

還可以利用block()函數(shù)來從Matrix中取出一個(gè)小矩陣來進(jìn)行處理,語法是matrix:block<p,q>(i,j),表示從原矩陣的(i,j)位置開始,截取出pxq大小的子矩陣,比如測(cè)試代碼:

    Eigen::MatrixXi randomI = MatrixXi::Random(6,6);    //隨機(jī)值的6x6矩陣
    std::cout << "------ randomI ------" << std::endl << randomI << std::endl;
    Eigen::MatrixXi smallI = randomI.block<3,3>(1,1);   //從(1,1)處截取一個(gè)3x3的矩陣
    std::cout << "------ smallI ------" << std::endl << smallI << std::endl;
?
    //運(yùn)行結(jié)果:
------ randomI ------
-13389 -12482   3334 -14515  12319  -1243
 -4442 -16231   3511   3528   7427  -8673
-11557 -16092 -10937   9283  14938  11869
-10948  -4002   5342   9915  13949  -9516
 16007   1037  -1613    651   1289   9163
 -1780   2332  -4846  -6490 -11720  11260
------ smallI ------
-16231   3511   3528
-16092 -10937   9283
 -4002   5342   9915    

數(shù)學(xué)運(yùn)算

Eigen庫(kù)重載了常用加減乘運(yùn)算符,而對(duì)于矩陣的除法,我們一般是求逆然后再轉(zhuǎn)換為乘法,使用起來比較簡(jiǎn)單,就不過多介紹了。

還有幾個(gè)常用的方法,必須要介紹一下,因?yàn)樵陧?xiàng)目中非常常見。

  • 矩陣轉(zhuǎn)置。調(diào)用transpose()方法即可求出一個(gè)矩陣的轉(zhuǎn)置矩陣。
  • 矩陣求逆。調(diào)用inverse()方法即可求出一個(gè)矩陣的逆矩陣。
  • 共軛矩陣。調(diào)用conjugate()方法可以求出共軛矩陣。

求解線性最小二乘方程組

此外,Eigen庫(kù)的最主要一個(gè)作用可以直接求解最小二乘方程組,對(duì)于方程組Ax=b,如果沒有確定解,可以找到一個(gè)向量x,使得其誤差平方值最小

我們可以回顧一下在線性回歸中,如何解出最佳擬合系數(shù)\theta,一般都是先構(gòu)建范德蒙矩陣,然后根據(jù)公式進(jìn)行計(jì)算。但是在Eigen中,可以直接使用bdcSvd類的solve()方法直接求解出最小二乘方程組的系數(shù)。

比如下面代碼中使用2種方法解最小二乘方程組:

    Eigen::MatrixXf X(4, 3);    //創(chuàng)建4x3的矩陣,表示有3個(gè)系數(shù)待求解,一共4個(gè)方程 
    Eigen::Vector4f Y;      //表示結(jié)果的長(zhǎng)度為4的列向量
    X << 0, 0, 1,
    1, 1, 1,
    4, 2, 1,
    9, 3, 1;
    Y << 2, 0, 3, 7;
?
    std::cout << "------ X ------" << std::endl << X << std::endl;
    std::cout << "------ Y ------" << std::endl << Y << std::endl;
    //使用bdcSvd方法
    Eigen::MatrixXf abc = X.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(Y);
    std::cout << "------ abc ------" << std::endl << abc << std::endl;
    //使用公式法
    Eigen::MatrixXf abc1 = (X.transpose() * X).inverse() * (X.transpose()) * Y;
    std::cout << "------ abc1 ------" << std::endl << abc1 << std::endl;
?
    //運(yùn)行結(jié)果:
------ X ------
0 0 1
1 1 1
4 2 1
9 3 1
------ Y ------
2
0
3
7
------ abc ------
 1.5
-2.7
 1.8
------ abc1 ------
     1.5
-2.70001
     1.8

到此這篇關(guān)于C++中線性代數(shù)計(jì)算Eigen庫(kù)的使用教程詳解的文章就介紹到這了,更多相關(guān)C++ Eigen庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入理解c++模板中的class與typename

    深入理解c++模板中的class與typename

    在c++Template中很多地方都用到了typename與class這兩個(gè)關(guān)鍵字,而且好像可以替換,是不是這兩個(gè)關(guān)鍵字完全一樣呢?下面這篇文章主要給大家介紹了關(guān)于c++模板中class與typename的相關(guān)資料,需要的朋友可以參考下。
    2017-07-07
  • C語言實(shí)現(xiàn)簡(jiǎn)單的五子棋小游戲

    C語言實(shí)現(xiàn)簡(jiǎn)單的五子棋小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡(jiǎn)單的五子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 如何理解C++指針常量和常量指針

    如何理解C++指針常量和常量指針

    這篇文章主要介紹了如何理解C++指針常量和常量指針,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • C語言數(shù)組實(shí)現(xiàn)三子棋應(yīng)用實(shí)例

    C語言數(shù)組實(shí)現(xiàn)三子棋應(yīng)用實(shí)例

    這篇文章主要為大家詳細(xì)介紹了C語言數(shù)組實(shí)現(xiàn)三子棋應(yīng)用實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++使用sort對(duì)容器排序的實(shí)現(xiàn)

    C++使用sort對(duì)容器排序的實(shí)現(xiàn)

    C++ STL 標(biāo)準(zhǔn)庫(kù)中的sort()函數(shù)專門用來對(duì)容器或普通數(shù)組中指定范圍內(nèi)的元素進(jìn)行排序,本文就詳細(xì)的介紹一下怎么實(shí)現(xiàn),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • C++編程析構(gòu)函數(shù)拷貝構(gòu)造函數(shù)使用示例詳解

    C++編程析構(gòu)函數(shù)拷貝構(gòu)造函數(shù)使用示例詳解

    這篇文章主要為大家介紹了C++編程構(gòu)造函數(shù)中析構(gòu)函數(shù)及拷貝構(gòu)造函數(shù)的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • C++編寫生成不重復(fù)的隨機(jī)數(shù)代碼

    C++編寫生成不重復(fù)的隨機(jī)數(shù)代碼

    本文給大家匯總介紹了3種c++實(shí)現(xiàn)生成不重復(fù)的隨機(jī)數(shù)的函數(shù),十分的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下。
    2015-05-05
  • C/C++哈希表優(yōu)化LeetCode題解997找到小鎮(zhèn)的法官

    C/C++哈希表優(yōu)化LeetCode題解997找到小鎮(zhèn)的法官

    這篇文章主要為大家介紹了C/C++哈希表優(yōu)化題解997找到小鎮(zhèn)的法官示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • C++圖像處理之雙邊濾波

    C++圖像處理之雙邊濾波

    這篇文章主要為大家詳細(xì)介紹了C++圖像處理之雙邊濾波,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • c語言中exit和return的區(qū)別點(diǎn)總結(jié)

    c語言中exit和return的區(qū)別點(diǎn)總結(jié)

    小編今天給大家整理了關(guān)于c語言中exit和return的不同點(diǎn)及相關(guān)基礎(chǔ)知識(shí)點(diǎn),有興趣的朋友們可以跟著學(xué)習(xí)下。
    2021-10-10

最新評(píng)論