C++入門(2)

行列演算テンプレートEigen

画面操作キー(全画面,ワイド表示,ソースコードハイライト)

Eigenライブラリの使用方法

  • Eigenライブラリを使った行列演算プログラミングでは下記が必要
    • Eigenライブラリのヘッダファイルの読み込み#include <Eigen/Dense>
    • コンパイル時,Eigenヘッダファイルへのパスの指定
  • ヘッダファイルへのパスは,環境に依存.以下は典型的なコンパイル例 (ソースコードファイルをprog1.cpp,実行ファイルをprog1とします):
  • g++ -std=c++11 -O3 -I/usr/include/eigen3  prog1.cpp -o prog1
  • ここで,"-std=c++11"はC++11の標準ライブラリを使う指定."-O3"は高速化のための最適化オプションで,"O"はオー
  • "-I/usr/include/eigen3"はインクルードパスの指定で,Eigenライブラリのヘッダファイルがあるディレクトリへのパスを示しています
  • 一般には,下記のMakefile(教科書p.108)を用意し,make prog1によりコンパイル
  • CXX = g++
    CXXFLAGS = -std=c++11 -O3 -I/usr/include/eigen3

行列やベクトルの宣言と演算例

ソースコードはprog1.cppとします.#include <Eigen/Dense>は,標準的なEigenライブラリを使うため.

#include <iostream>
#include <vector>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main(int argc, char* argv[]){
  MatrixXd A = MatrixXd::Ones(3,2);       // 全要素が1の3x2行列
  VectorXd v = VectorXd::Constant(2,7);   // 2次元ベクトルで全要素が7
  MatrixXd B = MatrixXd::Constant(2,3,5); // 2x3行列で全要素は5
  MatrixXd C = A.transpose();             // 行列Aの転置
  cout << C*A << endl << (A*v).transpose() << endl;
}
  • 要素が浮動小数点の行列MatrixXdやベクトルVectorXdを初期値を設定し宣言する例.".transpose()"は転置を返すメソッド(他にも多数あり).行列同士の積や行列とベクトルの掛け算(+結果の転置)の例.実行例は
  • ./prog1
    3 3
    3 3
    14 14 14

行列やベクトルの操作(1)

  • Eigenライブラリが用意する,行列やベクトル間の積,転置,以外の操作も多数
    #include <iostream>
    #include <vector>
    #include <Eigen/Dense>
    using namespace Eigen;
    using namespace std;
    int main(int argc, char* argv[]){
      MatrixXd A(2,4); // 2x4の行列(値は未設定)の宣言
      A << 2,3,4,5,    // 行列に値を代入する1方法
           6,7,8,9;    // 見た目通りに入る(行優先)
      MatrixXd B = MatrixXd::Constant(2,4,2); // 2x4行列で全要素は2 
      cout << A(1,0) << endl << A.rowwise().mean() << endl;//要素の参照は(添字,添字).行方向の平均を返すメソッド
      cout << A.array()+B.array() << endl << A.array()*B.array() << endl;//.array()により要素ごとの四則演算可
    }
  • ./prog1
    6
    3.5
    7.5
     4  5  6  7
     8  9 10 11
     4  6  8 10
    12 14 16 18
    

行列やベクトルの操作(2)

  • 対角成分の取り出し,ベクトルを対角成分に持つ対角行列生成,要素ごとの平方根,対角成分和(.trace()
    #include <iostream>
    #include <vector>
    #include <Eigen/Dense>
    using namespace Eigen;
    using namespace std;
    int main(int argc, char* argv[]){
      MatrixXd A(3,3);             // 3x3の行列(値は未設定)の宣言
      A << 1,2,3,  4,5,6, 7,8,9;   // 値の代入(行優先)
      VectorXd v(2);               // 2次元ベクトルの宣言
      v << 3,5;                    // 値代入
      VectorXd a = A.diagonal();   // 行列の対角成分を要素とするベクトルへの変換
      MatrixXd V = v.asDiagonal(); // ベクトルの要素を対角成分とする対角行列への変換
      MatrixXd B = A.cwiseSqrt();  // 行列の各要素をその平方根に変換
      cout << A.trace() << endl << a << endl << V << endl; // .trace()は対角成分和を返すメソッド
    }
  • ./prog1
    15
    1
    5
    9
    3 0
    0 5
    

外部ファイルからの読み込み

  • 以下をdata2.datとして保存.ファイル上,特徴ベクトルは,各行に格納されているとみなす.これを行列に読み込むとき,特徴ベクトルは列ベクトルになり格納される(列優先).下記は3x2の行列である.vector配列から行列への変換はMapを使うが,その際に行数と列数が必要(推定方法はp.109のcalcCov.cpp参照)
    1 2 3
    7 8 9
    
    #include <iostream>
    #include <vector>
    #include <fstream>
    #include <Eigen/Dense>
    using namespace Eigen;
    using namespace std;
    int main(int argc, char* argv[]){
      string fileName = argv[1];
      ifstream ifile( fileName );
      vector<double> vec;
      double d;
      while( ifile >> d ) vec.emplace_back(d);
      MatrixXd X = Map<MatrixXd>(&(vec[0]),3,2); // 引数は(ベクトルの先頭アドレス,行数,列数)
      cout << X << endl;
    }
  • 実行すると,読み込んだ3x2の行列が出力される

<Thank You!>

C++入門(2) 内山俊郎