2015-11-17 49 views
3

我:與maxCoeff奇怪的錯誤在本徵

VectorXd my_vector; 
MatrixXd my_matrix; 

和尺寸都在表達波紋管兼容。

我記得在本徵文檔,它始終是更好地計算表達式作爲一個整體,而不是評估小chuncks,然後重新組合的結果,因爲它給了本徵更多的機會進行優化。

考慮到這一點,我將使用:

// (1) 
int index; 
(my_vector.transpose() * my_matrix.leftCols(n_cols+1)).maxCoeff(&index); 

而非:

// (2) 
int index; 
RowVectorXd temp = my_vector.transpose() * my_matrix.leftCols(n_cols+1); 
temp.maxCoeff(&index); 

然而,當同時使用n_cols = 1(1)崩潰(2)代替(1)準確地在同一個地方似乎總是工作。 (請注意,my_matrix有超過1列...)

問題:
爲什麼(1)在(2)不會崩潰?
如何防止(1)在保持單一表達式的同時崩潰?

錯誤來自Eigen的內部機器斷言,在我看來,這是因爲在(1)maxCoeff似乎並沒有意識到它被稱爲行矢量而不是一般矩陣 - 請糾正我,如果我錯了。

回答

3

您也可以使用.eval()一種變通方法。這實際上是一樣的(2),只是沒有額外的代碼行:

(my_vector.transpose() * my_matrix.leftCols(n_cols + 1)).eval().maxCoeff(&index); 

關於本徵的內部工作,當你調用maxCoeff的情況下,(1)這是被調用的對象(如你明確希望)通過調用mat.coeff(0,0)觸發的惰性評估構造(在這種情況下爲GeneralProduct<Transpose<..>,Block<...> >),其中matGeneralProduct。在內部,mat(n_cols + 1)列與之相對應的是該行的斷言(Matrix<Scalar,1,1> result = *this;)後需要1 這是什麼原因造成的評價,所以我們希望每一次只有一個元素來評估。如果沒有聲明,試圖將*this分配給result,會觸發調整大小,從而導致程序崩潰。

使用臨時對象時,對象是Matrix<double,1,-1,1,1,-1>,因此coeff(i,j)只是對m_storage.data()[colId + rowId * m_storage.cols()]的簡單調用。

所有這一切都變得在本徵3.3一個模擬點作爲整個coeff(i,j)現在return m_evaluator.coeff(row, col);

TLDR

升級到本徵3.3(阿爾法)和問題消失。

+0

這是否只保存一行代碼或它也允許Eigen優化整個計算?我不知道Eigen是否真的這樣做,但我會想象一個完全優化的計算只會循環一次,而也許'eval()'會強制第一個循環,然後'maxCoeff'將不得不運行第二個循環循環? – Julien

+0

這是正確的。 'eval()'強制在內存中保存一個臨時內存,隨後運行'maxCoeff'。 –

+0

感謝您的額外解釋。對於TLDR:我必須使用我公司的版本,並且他們不會轉換爲alpha版本...對於更詳細的解釋,我有點失去它,特別是我不明白背後的原因只有一列......這只是一個真正的'錯誤',是要在下一個版本中解決的? – Julien

2

要完成Avi的回答,首先要補充的是,要有效評估產品,必須將產品評估爲臨時產品,因此無論使用Eigen的版本,致電.eval()都是完美無缺的。

,你正在觀察當前聲明:

Assertion failed: (this->rows() == 1 && this->cols() == 1), function coeff, file ../eigen3.2/Eigen/src/Core/ProductBase.h, line 148 

是確保產品表現不計算係數明智的事故(除內的產品)。可以在斷言消息中添加此解釋以使其更清楚。然而,在你的情況下,你自己並沒有明確地調用coeff()operator(i,j),這就是Eigen中的一個錯誤,更確切地說是Eigen::Visitor,它應該爲你評估嵌套的產品表達式。這將在3.2.8中修復。

最後,如果你知道這兩個n_cols+1my_vector是非常小的,你能避免這種臨時使用一個懶惰的產品:

my_vector.transpose().lazyProduct(my_matrix.leftCols(n_cols+1)).maxCoeff(&index); 

編輯:備案這裏是fix

+0

感謝您的解釋!所以只是爲了讓事情變得完全清楚:我的版本(2)完全等同於Avi的'eval()'版本嗎?或者讓Eigen使用'eval()'創建並處理它自己的「隱藏的」臨時文件會更好嗎? – Julien

+0

是的,有相同的。 – ggael