web-dev-qa-db-ja.com

固有行列をC配列に変換

Eigen ライブラリは、既存のメモリをEigen行列にマッピングできます。

float array[3];
Map<Vector3f>(array, 3).fill(10);
int data[4] = 1, 2, 3, 4;
Matrix2i mat2x2(data);
MatrixXi mat2x2 = Map<Matrix2i>(data);
MatrixXi mat2x2 = Map<MatrixXi>(data, 2, 2);

私の質問は、固有行列(例:Matrix3f m)からc配列(例:float [] a)を取得するにはどうすればよいですか?固有行列の実際のレイアウトは何ですか?実際のデータは通常のc配列のように保存されていますか?

49
lil

Eigen Matrixクラスの data() メンバー関数を使用できます。デフォルトのレイアウトは、多次元C配列の行優先ではなく列優先です(Matrixオブジェクトの作成時に選択できます)。スパース行列の場合、前述の文は明らかに当てはまりません。

例:

ArrayXf v = ArrayXf::LinSpaced(11, 0.f, 10.f);
// vc is the corresponding C array. Here's how you can use it yourself:
float *vc = v.data();
cout << vc[3] << endl;  // 3.0
// Or you can give it to some C api call that takes a C array:
some_c_api_call(vc, v.size());
// Be careful not to use this pointer after v goes out of scope! If
// you still need the data after this point, you must copy vc. This can
// be done using in the usual C manner, or with Eigen's Map<> class.
51
janneb

通常のデータ型を固有行列型に変換するには

  double *X; // non-NULL pointer to some data

次のようなマップ機能を使用して、nRows x nColsサイズのダブルマトリックスを作成できます。

  MatrixXd eigenX = Map<MatrixXd>( X, nRows, nCols );

固有行列タイプを通常のデータタイプに変換するには

  MatrixXd resultEigen;   // Eigen matrix with some result (non NULL!)
  double *resultC;        // NULL pointer <-- WRONG INFO from the site. resultC must be preallocated!
  Map<MatrixXd>( resultC, resultEigen.rows(), resultEigen.cols() ) =   resultEigen;

このようにして、固有行列から出たり入ったりすることができます。完全なクレジットは http://dovgalecs.com/blog/eigen-how-to-get-in-and-out-data-from-eigen-matrix/ に移動します

15
GPrathap

もう一度マップ機能を使用する必要があります。こちらの例をご覧ください: http://forum.kde.org/viewtopic.php?f=74&t=95457

3
Prashanth

配列が2次元の場合、保存順序に注意する必要があります。デフォルトでは、Eigenは行列を列優先順に格納します。ただし、配列を固有行列に直接変換するには、行優先の順序が必要です。このような変換がコード内で頻繁に実行される場合、対応するtypedefを使用すると役立つ場合があります。

using namespace Eigen;
typedef Matrix<int, Dynamic, Dynamic, RowMajor> RowMatrixXi;

このような定義を使用すると、元の配列の順序を維持しながら、単純でコンパクトな方法で配列から固有行列を取得できます。

C配列からEigen :: Matrixへ

int nrow = 2, ncol = 3;
int arr[nrow][ncol] =  { {1 ,2, 3},  {4, 5, 6} }; 
Map<RowMatrixXi> eig(&arr[0][0], nrow, ncol);

std::cout << "Eigen matrix:\n" << eig << std::endl;

// Eigen matrix:
// 1 2 3
// 4 5 6

反対方向では、Mapを使用して、固有行列の要素をCスタイルの配列に直接転送できます。

Eigen :: MatrixからC配列へ

int arr2[nrow][ncol];
Map<RowMatrixXi>(&arr2[0][0], nrow, ncol) = eig;

std::cout << "C array:\n";
for (int i = 0; i < nrow; ++i) {
  for (int j = 0; j < ncol; ++j) {
    std::cout << arr2[i][j] << " ";
  }
  std::cout << "\n";
}

// C array:
// 1 2 3 
// 4 5 6 

この場合、元の行列eigは行優先レイアウトで保存する必要がないことに注意してください。 Mapで行優先順を指定するだけで十分です。

3
RHertel

私がそれを試してみると、segfaultの上にMapがあるソリューションがあります(上記のコメントを参照)。

代わりに、Eigen :: Matrixからstd :: vectorにデータをコピーする、私にとって有効な解決策があります。 Map/copyの結果を保存するために、ベクターにスペースを事前に割り当てます。

Eigen::MatrixXf m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = 0;

cout << m << "\n";

// Output:
//    3  -1
// 2.5   0

// Segfaults with this code: 
//
// float* p = nullptr;
// Eigen::Map<Eigen::MatrixXf>(p, m.rows(), m.cols()) = m;

// Better code, which also copies into a std::vector:

// Note that I initialize vec with the matrix size to begin with:
std::vector<float> vec(m.size());
Eigen::Map<Eigen::MatrixXf>(vec.data(), m.rows(), m.cols()) = m;

for (const auto& x : vec)
  cout << x << ", ";
cout << "\n";

// Output: 3, 2.5, -1, 0
1
eraoul