本篇內容主要解決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;
}