Eigen
で行優先の行列を行優先のベクトルに変換する時、ベクトルのイテレータをstd::contiguous_iterator
にする方法¶
この記事は私がEigen
に立てたイシューが解決される見込みがないので、埋もれる前に残しておくつもりで書きました。
問題点¶
Eigen
では行列と配列のイテレータがstd::contiguous_iterator
コンセプトを満たすようになりました123。
ただし、とある条件を満たす必要があり、reshaped
メンバ関数で行列をベクトルに変換する場合は変形後のベクトルと変形前の行列の格納順が一致しなくてはいけません。
reshaped
で返されるベクトルの格納順はそのベクトルが行ベクトルなら行優先、列ベクトルなら列優先です5。
しかし、変形後のベクトルの格納順はたとえ明示的にEigen::StorageOptions::RowMajor
を渡しても必ず列ベクトルを返すため6、変形前の行列が行優先の場合だと不一致になってしまいます。
#include <span>
#include "Eigen/Dense"
int main() {
Eigen::Matrix3f m;
std::span<const float, 9>(m.reshaped<Eigen::StorageOptions::RowMajor>().begin(), 9); // エラー
return 0;
}
解決策¶
Eigen
にはEigen::fix
という、関数によって構築されるオブジェクトの整数テンプレート引数にコンパイル時整数を指定することができる関数が用意されています4。
この関数を使って、以下のように行数と列数を指定すると変形後のベクトルは行ベクトルとなり、行優先の行列を変形しても格納順が一致します。
#include <span>
#include "Eigen/Dense"
int main() {
Eigen::Matrix3f m;
std::span<const float, 9>(
m.reshaped<Eigen::StorageOptions::RowMajor>(Eigen::fix<1>, Eigen::fix<9>).begin(), 9);
return 0;
}