Eigenは, まあ手っ取り早く行列計算をするパッケージです.とにかく簡単にプログラムを書くのが目的らしいですよ.でも,もう一つの特徴は,通常あり得ないほど計算が高速であることです.
なんかこのページ,中身が古いというか要点外しすぎで萎えるんだけど?
Matrix
#include <Eigen/Dense> ←じゅげーむ!
Eigen::MatrixXd myArray(5,3);
Eigen::MatrixXd myBrray(3,5);
Eigen::MatrixXi myCrray(5,5);
これで5x3と3x5の蜜行列ができると. 要素のアクセスは,配列名(行,列)ばい.ちなみにXdのdが倍精度, Xi のiが整数じゃき.
myArray(0,0)=2.5;//0から始まるのがお茶目 std::cout << "Rows= " << myArray.rows() << " Cols= " << myArray.cols() << std::endl;
でもこれ,めんどくさかろ?下の方がぱっと見がええよ?
myArray << 2.5, 3.1, 4.2, 5.2, 3.3, 1.0, 3.1, 5.2, 5.2, -1.2,4.2, std::sqrt(2.5), 5.3, 2.2, 5.6;
画面に書くのもちょろいっちゃん:
std::cout << myArray << std::endl; std::cout << myArray.row(3) << std::endl; //0から数えて3(数学では4列目というやつ) std::cout << myArray.col(1) << std::endl; //律儀に縦ベクトルで出力するので注意
もちろん途中でresize可能:
Eigen::MatrixXd myDrrays; myDrrays=myArrray; Eigen::MatrixXd myErrays; myErrays.resize(100,100);
行列ば足したり掛けたりしてよか:
auto D=myArray*myBrray;
ばってん下のはできんと. 倍精度なのか整数なのか,わかりよらん. 掛け算というか代入も無理.
auto E=D*myCrray;
こういう時には, cast<typename T>()関数ば使うったい:
Eigen::MatrixXd myFrrays=myCrray.cast<double>(); auto G=D*myCrray.cast<double>();
みゃるほどみゃーーー
他にも, 転置行列を得る transpose() とか trace(), diagonal()とか,まあ想像できるわな.
対角行列には特別な奴がおるったい:
using DiagonalXd=Eigen::DiagonalMatrix<double,Eigen::Dynamic> DiagonalXd KAKU; KAKU.resize(12);//引数は1つ //KAKU(2)=1.5; //なぜかこれはできん. KAKU.diagonal()(2)=1.5; //std::cout << KAKU //これも,できにゃあ Eigen::MatrixXd pKAKU=KAKU; std::cout << pKAKU;
不思議な奴やね
Vector
Matrixを扱うにはベクトルが必要だが, これは VectorXd とかである. まあ普通に計算できるが, 内積は
Eigen::VectorXd A(3), B(3); A << 0,1,2; B << 1,2,3; double innter=A.dot(B); //これが内積
3次元に特化した Vector3d では,外積もある:
Eigen::Vector3d A, B; A << 0,1,2; B << 1,2,3; auto C=A.cross(B); //これが内積
これがあれば, 行列の列を入れ替えるとかが簡単なのよ:
Eigen::MatrixXd VV(4,5); VV << 1,2,3,4,5, 11,12,13,14,15, 21,22,23,24,25, 31,32,33,34,35; Eigen::VectorXd XX(4); XX << -1.2,-1.3,-1.4,-1.5; VV.col(2)=XX;
お前がstd::vector<double>とか持っているならしょきかはかんたんじゃき(C++17)
std::vector<double> Boke {1.2, 1.3, -2.4};
Eigen::Vector3d Kasu(Boke.data()); // Bokeの成分でKasuを作成
row(), col()の実態
実はrow(), col()で得られるのはブロック要素への参照というものである. いいですか, 参照であるし, ブロック要素なんですよ.ベクトルではないのです. 例えば 1xN 行列のj列を取り出そうとして
double X=N.col(j); // これはできない.結果は行列なんで double X=N.col(j).value(); //これはできる
なーんと.ああそれと,Eigenではめっちゃ遅延評価するんで,普通に書いたら式のままでビルドされてしまう.実行時に値が確定する.だからauto使う時は注意ね.
auto B=A.transpose(); // B変数は行列型ではなく数式型. 行列がよかなら auto B=A.transpose().value() と書いて遅延評価ばなしにせんとね
ブロック行列
行列の一部を取り出せる.
Eigen::Matrix<double,4,4> MM; MM << 1,2,3,4, ... Eigen::Matrix<double,1,3> m1; m1=MM.block<1,3>(0,0);//1x3行列, 0,0起点
Matrix Reloaded
じつはMatrixは線形演算しかサポートしていない.もっと色々できるのがArrayである. Matrix MをArrayにするには M.array() を,Array AをMatrixにするには A.matrix() を使う:
auto X=myArray.arrat(); //XはArray型 auto Y=X.matrix(); //YはMatrix型
線形演算
いよいよ本領発揮だ.
QR分解
m x n 行列 Aは, m x m 直交行列 Q と m x n 上三角行列に分解できる. ハウスホルダー変換で実現するのが A.colPivHouseholderQr() であり, ハウスホルダー変換結果を表す HouseholderQrクラスのオブジェクトの参照を戻す.というわけで, A x = b を解きたい場合には, A.colPivHouseholderQr().solve(b) でOK. 詳細を知りたければ戻ってきたオブジェクトに尋ねれば良い.
分解は他にも色々準備されている.
固有値固有ベクトル
もうマニュアル見た方が
行列式と逆行列
正方行列では, A.determinant() と A.inverse() が利用できると.ばってん#include <Eigen/LU> をわすれんよう気いつけるとよ.
計算速度
計算速度は実に謎めいている. 準備されている関数は, ヘッダーライブラリーであるにも関わらず,速い!なんだかよくわからないがコンパイル済みのBLASよりも速い! わけがわからん. ところが,自分で書くと遅い.おかしい.なんだろうこれ
MatrixXd G(N,M)=...定義...; std::cout << G.colwise().norm()<< std::endl
はひどく高速だが
MatrixXd G(N,M)=...定義...; for(int i=0;i<G.cols();i++) std::cout << G.col(i).norm()<< std::endl
はひどく低速である. なんでやねんこれ?だから
MatrixXd G(N,M)=...定義...; auto NORM=G.colwise().norm(); std::cout << NORM.col(12) << std::endl;
が高速で便利なのよ. 要素アクセスで,何か最適化がかかるのだろうけど・・・
丸田先生の解釈では,テンプレートだし,オブジェクトの実態が決まるまでコンパイルできないし,コンパイルするときには行列のサイズやら全部決定しているから,クソほど最適化がかかるのではないか?
だってさー.そんなもんなんですかね.まあええわ,クソほど早いのはいいことだし