Skip to content

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;
}

参考