読者です 読者をやめる 読者になる 読者になる

アルマジロその1. 行列操作編

ここでは, RcppArmadilloにおける行列の初期化などを紹介します. 特に説明もせず, バンバン例を載せるので気になった所をコピペして結果を確認してください.

おまじない
library (Rcpp)
library (inline)
library (RcppArmadillo)
library (Matrix) # for sp_mat (疎行列に必要)
行列の初期化
# 配列の初期化 
# 複素行列(cx) 疎行列(sp)は, 必要になったらまた調べる
# rowvec, colvecをつくるときは, arma::randn(1, 5)とかにする
# arma::randn<arma::mat>(1,5)とかにすれば, そのまま使える
src <- 'arma::mat A = arma::mat(5,5);                     // アロケート 第三引数にfill値をいれてもよい
        A.randn();                                        // .fill(0)で全て0になったりもする
        arma::mat B  = arma::mat(5,5, arma::fill::randu); // 一様乱数で初期化
        arma::mat C  = arma::zeros(5,5);                  // すべて0
        arma::mat D  = arma::ones(5,5);                   // すべて1
        arma::mat E  = arma::eye(5,5);                    // 単位行列
        arma::mat F  = arma::randn(5,5);                  // 標準正規乱数
        arma::cube G = arma::randu(5,5,2);                // 三次元配列と, 一様乱数
        arma::vec H  = arma::randu(5);                    // ベクトル(列)
        arma::ivec I = arma::randi(5, arma::distr_param(-10, 10));  // 1から10までの整数から5つ, imat, icubeもある
        arma::vec J  = arma::linspace(10, 14, 10);         // ivecはダメだよ, linspaceはseqと同じなので, seq(from, to, length.out)
        arma::sp_mat K = arma::sp_mat(5,5);                // RのdgCMatrixクラスで出力. Matrixが必要だよ
        arma::mat Q = "1 2 3; 4 5 6;";
        
        return Rcpp::List::create(Rcpp::Named("A") = A, 
                                  Rcpp::Named("B") = B,
                                  Rcpp::Named("C") = C,
                                  Rcpp::Named("D") = D,
                                  Rcpp::Named("E") = E,
                                  Rcpp::Named("F") = F,
                                  Rcpp::Named("G") = G,
                                  Rcpp::Named("H") = H,
                                  Rcpp::Named("I") = I, 
                                  Rcpp::Named("J") = J,
                                  Rcpp::Named("K") = K, 
                                  Rcpp::Named("Q") = Q);      
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
行列初期化2(疎行列)
src <- 'arma::sp_mat A = arma::sprandu(10, 10, 0.1); // 密度.1で一様乱数をいれた疎行列, sprandnもある
        arma::sp_mat B = arma::spones(A);              // Aの非ゼロ要素を1に変換
        arma::sp_mat C = arma::speye(10, 10);        // 疎行列の対角行列
        return Rcpp::List::create(A, B, C);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
次元いじり
# 次元変え
src <- 'arma::mat A = Rcpp::rnorm(10, 0, 1); 
        arma::mat B;
        arma::mat C;
    arma::mat E;
        A.reshape(5,2);       // 5×2
        B.copy_size(A);             //Aと同じ大きさの行列つくる
        C = repmat(A, 4, 5);        //matlabと同じ
        arma::mat D = A;            //このコピーはあんましよくなさそう
        arma::vec v = vectorise(A, 0); // Aの要素で一列のベクトルをつくる, 第二引数を1にすると行ベクトルになる
        v.t().print();
    E = arma::fliplr(A);       //列を入れ替えたAをこぴ. flipudは行を入れ替える
        A.swap_rows(0, 4);          //Aの一行目と五行目を入れ替える. colsもある
        //A.reset();               //<0,0>matrix
        //A.set_size(2, 5);
        //A.resize(10,10);
        return wrap (0);      
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
行列の基本情報
# 行列の特性にアクセス
# 他にも, スパース行列の非0要素を把握するn_nonzeroがある
# 3次現配列で, 3次目を指定するときは .slices(k)や, .slices(t,u)など
src <- 'arma::mat A = Rcpp::rnorm(10, 0, 1); // 次元がなく, 要素だけ
        A.reshape(5,2);
        int n = A.n_cols, k = A.n_rows, nk = A.n_elem, nk2 = A.size();
        A.clear(); //A のエレメントを消す
        A.empty(); //Aが要素を持たないときtrue
        bool a, b, c, d;
        a = A.is_square();
        b = A.is_vec();
        c = A.is_rowvec();
        d = A.is_colvec();
        LogicalVector D = Rcpp::LogicalVector::create(a, b, c, d);
        // return wrap(A.empty());
        return Rcpp::List::create(Rcpp::Named("ncol") = n, 
                                  Rcpp::Named("nrow") = k,
                                  Rcpp::Named("elem") = nk, 
                                  Rcpp::Named("nk2")  = nk2, 
                                  Rcpp::Named("D")    = D);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
対角成分
# 対角成分関係
src <- 'arma::mat A = Rcpp::rnorm(25, 0, 1);     // 次元がなく, 要素だけ
        A.reshape(5,5);
        arma::vec a = A.diag();                  // 列ベクトルになっているよ
        arma::vec b = A.diag(1);
        arma::vec c = A.diag(-2);
        arma::vec d = arma::diagvec(A);          // aと同じ
        double    e = trace (A);
        arma::mat B = diagmat (A);  // Aの対角成分だけの行列
        arma::mat C = diagmat (a);  // Bと同じになる


        return Rcpp::List::create(Rcpp::Named("A") = A, 
                                  Rcpp::Named("a") = a,
                                  Rcpp::Named("b") = b,
                                  Rcpp::Named("c") = c,
                                  Rcpp::Named("d") = d,
                                  Rcpp::Named("e") = e,
                                  Rcpp::Named("B") = B,
                                  Rcpp::Named("C") = C,
                                  Rcpp::Named("v") = v);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
転置とか
# 転置, 三角, 対称とか
src <- 'arma::mat A = Rcpp::rnorm(25, 0, 1); // 次元がなく, 要素だけ
        A.reshape(5,5);
        arma::mat At = A.t(); // もしくは, trans(A)
        arma::mat U  = trimatu(A); // 上三角を抽出
        arma::mat L  = trimatl(A);
        arma::mat B  = symmatu(A); // 上三角を使って対称行列をつくる
        arma::mat C  = symmatl(A);
        return Rcpp::List::create(Rcpp::Named("At") = At,
                                  Rcpp::Named("A")  = A, 
                                  Rcpp::Named("U")  = U,
                                  Rcpp::Named("L")  = L,
                                  Rcpp::Named("B")  = B,
                                  Rcpp::Named("C")  = C); // Rcpp::はなくてもよい?
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
交換
# 交換
# swap
src <- 'arma::mat A = arma::zeros(5,5);
        arma::mat B = arma::ones(7, 6);
        A.swap(B);

        return Rcpp::List::create(A, B);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()

行列の結合
# 行列の接合
# .insert_rowsもある
# .insert_slicesもある(for cuve)
src <- 'arma::mat A = arma::mat (5,10,arma::fill::randu); 
        arma::mat B = arma::mat (5,2,arma::fill::randu);
        arma::mat C = arma::ones (5, 5);
        arma::mat D, E;
        A.insert_cols(2, B);  // 3列目にBを入れる
        B.insert_cols(1, 5);  // 2列目に, 5×5の行列を入れる
        C.insert_cols(5, A);
        D = join_rows (C, A); // Cと同じ, join_rowsはRのcbindと同じ
        E = join_horiz(A, B); // cbind(A, B), join_vertがrbind
        return Rcpp::List::create(Rcpp::Named("A")  = A, 
                                  Rcpp::Named("B")  = B, 
                                  Rcpp::Named("C")  = C, 
                                  Rcpp::Named("D")  = D, 
                                  Rcpp::Named("E")  = E);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()

列ごとにhogehoge
# apply的な.
# .cols(0, 2)とかで, 1, 2, 3列にアクセス
# .col(0)で, 1列目だけにアクセス
# indicesを使うともっと便利
# each_row()もある
# cubeはslices
src <- 'arma::mat A = Rcpp::rnorm(25, 0, 1);     // 次元がなく, 要素だけ
        A.reshape(5,5);
        arma::vec b = arma::linspace(10, 14, 5); // 10から14の列ベクトル
        A.cols(0, 3).each_col() += b;            // 列ごとにbを足す, 当然, .colsはなくて良い
        
        arma::uvec indices(1);  // インデックスの大きさ
        indices(0) = 1;         
        A.each_col(indices) = b; //代入

        arma::mat B = A.col(0);

        return wrap(B);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()
サブマトにアクセス
# 部分的操作
src <- 'arma::mat A = arma::zeros(5,5); 
        A.submat(0,1, 2,3) = arma::randn(3,3);                  // サブマトの左上と右下の指定. ここでは, A[1,2]からA[3,4]
        A(arma::span(0,2), arma::span(1,3)) = arma::randn(3,3); // A[1:3, 2:4] in R
        arma::mat B = A.submat(0, 1, 2, 3);
        arma::mat C = A(arma::span(0,2), arma::span(1,3));
        arma::mat D = A(0, 0, arma::size(3,3));                 // A[1,1]を左上にして, 3×3の行列をとる


        arma::mat X = arma::randn(5,5);
        arma::uvec indices;     // 参照インデックス用
        // Xの要素のうち, 正要素を取り出す
        //return wrap(X>0);
        //return wrap(find(X>0));
        indices = find(X>0);
        X.elem(indices).print();
        // Xの要素のうち, 0以上に10を足す
        indices = find(X>0);
        X.elem(indices) += 10;
        X.print();
        // 負の値をゼロにする
        // くどいので, もっといい方法ありそう
        indices = find(X<0);
        arma::vec tem;
        tem.copy_size(indices);
        tem.fill(0);
        X.elem(indices) = tem;
        X.print();
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()


print

# printデバック
src <- 'arma::mat A = arma::mat (2,2,arma::fill::randu); 
        A.print("A:");          // Aの出力
        A.raw_print();          // 丸めずに出力
        return wrap(0);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()


Rcout
# Rcout
src <- 'arma::mat A = arma::mat (2,2,arma::fill::randu); 
        Rcout << "The value is " << A.row(1)(0) << std::endl;
        return wrap(0);
'
fun <- cxxfunction (body = src, plugin = "RcppArmadillo")
fun ()