Eigen在使用高維矩陣時棧溢出,報錯OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG,解決方法及高維矩陣運算

  本篇內容主要解決Eigen大型矩陣的構建、賦值、運算過程中,內存溢出的問題,報錯:OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG!

1.問題陳述

  在使用Eigen中,創建高維矩陣和運算的時候,一直報一個錯誤,大致內容如下:

In file included from /usr/include/eigen3/Eigen/Core:297:0,
                 from /home/mm/Cpptest/untitled3/main.cpp:3:
/usr/include/eigen3/Eigen/src/Core/DenseStorage.h: In instantiation of ‘void Eigen::internal::check_static_allocation_size() [with T = double; int Size = 1562500]’:
/usr/include/eigen3/Eigen/src/Core/DenseStorage.h:110:41:   required from ‘Eigen::internal::plain_array<T, Size, MatrixOrArrayOptions, 16>::plain_array() [with T = double; int Size = 1562500; int MatrixOrArrayOptions = 0]’
/usr/include/eigen3/Eigen/src/Core/DenseStorage.h:187:38:   required from ‘Eigen::DenseStorage<T, Size, _Rows, _Cols, _Options>::DenseStorage() [with T = double; int Size = 1562500; int _Rows = 1250; int _Cols = 1250; int _Options = 0]’
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:457:55:   required from ‘Eigen::PlainObjectBase<Derived>::PlainObjectBase() [with Derived = Eigen::Matrix<double, 1250, 1250>]’
/usr/include/eigen3/Eigen/src/Core/Matrix.h:259:41:   required from ‘Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::Matrix() [with _Scalar = double; int _Rows = 1250; int _Cols = 1250; int _Options = 0; int _MaxRows = 1250; int _MaxCols = 1250]’
/home/mm/Cpptest/untitled3/main.cpp:11:53:   required from here
/usr/include/eigen3/Eigen/src/Core/util/StaticAssert.h:32:40: error: static assertion failed: OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
     #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
                                        ^
/usr/include/eigen3/Eigen/src/Core/DenseStorage.h:33:3: note: in expansion of macro ‘EIGEN_STATIC_ASSERT’
   EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);

這裏面最重要的一個信息就是,下面這一個錯誤提示:

error: static assertion failed: OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
     #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);

  主要原因就是:棧溢出

2.解決辦法:

  要想解決這個問題,我們只需要將創建的靜態矩陣,改成動態矩陣。
例如,先前我們創建的如下面形式的矩陣:

Eigen::Matrix<double, 500, 500> matrix_NN;

將上一行代碼改成下面形式:

Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_NN;

  這裏的Eigen::Dynamic表示的是矩陣的維數是動態的,在賦值或者運算的時候,自動產生對應的維數大小。
注意:因爲我們定義的矩陣是動態維數,所以有時候可能必須要先“固定(有別於靜態矩陣的固定)”維數,那麼可以通過賦值的方式,下面介紹幾個賦值方式使其產生“固定”維數的方法:
  1).用隨機值矩陣初始化

matrix_NN = Eigen::MatrixXd::Random(500, 500);

  2).用單位矩陣初始化

matrix_NN = Eigen::MatrixXd::Identity(500, 500);

  3).用零矩陣初始化

matrix_NN = Eigen::MatrixXd::Zero(500, 500);

  有一點需要強調: 雖然我們可以使用任何維度的矩陣去賦值或者初始化matrix_NN,但是始終沒有改變它是動態矩陣的性質,也就是維數運行過程始終可以變化,這一點兒不同於靜態矩陣,靜態矩陣編譯時就確定了維度,運行時不能變。

補充:靜態矩陣和動態矩陣的區別:
  動態矩陣和靜態矩陣:動態矩陣是指其大小在運行時確定,靜態矩陣是指其大小在編譯時確定。
  MatrixXd:表示任意大小的元素類型爲double的矩陣變量,其大小隻有在運行時被賦值之後才能知道。
  Matrix3d:表示元素類型爲double大小爲3*3的矩陣變量,其大小在編譯時就知道。

3.題外話

  矩陣使用了動態矩陣之後,就可以做大型矩陣的運算了,我將一個小例子放在這裏與大家分享,我將一個400維的矩陣,進行方程求解,在我的已經用了好多年的美帝良心機(聯想)筆記本上,分別使用直接求逆的方法和QR分解的方法,運行時間如下:

Direct guidance uses times: 315363ms
QR uses times: 832.552ms

代碼如下,如果你有興趣可以在你的電腦上試一下:

#include <iostream>
#include <ctime>
#include <Eigen/Core>
#include <Eigen/Dense>

using namespace std;
#define MATRIX_SIZE 400

int main() {
    //This codes mainly use to solve the equation, matrix_NN *x = v_Nd
    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> matrix_NN;
    matrix_NN = Eigen::MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);
    Eigen::Matrix<double, MATRIX_SIZE, 1> v_Nd;
    v_Nd = Eigen::MatrixXd::Random(MATRIX_SIZE, 1);

    clock_t time_stt = clock();
    Eigen::Matrix<double, MATRIX_SIZE, 1> x = matrix_NN.inverse() * v_Nd;
    cout << "Direct guidance uses times: " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;

    time_stt = clock();
    x = matrix_NN.colPivHouseholderQr().solve(v_Nd);
    cout << "QR uses times: " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章