首页 > 解决方案 > 使用犰狳访问下三角元素的更有效方法

问题描述

是否有更有效的方法来创建包含矩阵下三角元素的向量?对于某些算法,将这些元素放在一个向量中是很有用的。

但是,当我更喜欢指针时,下面的代码显然会创建副本。鉴于元素位置的非连续性质,这可能是不可能的。

我想到的一种替代方法是通过find(trimatu(inmat)!=0)左右创建一个索引矩阵,但我无法想象这样会更有效率。在双精度矩阵中找到精确的零通常不是很快,而且在我试图提取的三角形内也可能有实际的 0。这里已经讨论了这些方面的内容(C++ Armadillo Access Triangular Matrix Elements),但是,这个问题已经有 5 年历史了,从那时起,犰狳已经有了很大的改进。

vec trimat2vec(mat const& inmat){

  int K = inmat.n_rows;
  int p = K*(K-1)/2;
  vec out(p);

  int counter=0;
  for(int i=0; i<K; i++){
    for(int j=1; j<K; j++){
      if(i<j){
        out(counter)=inmat(j,i);
        counter+=1;
      }
    }
  }
  return(out);
}

标签: c++armadillo

解决方案


好的,有了新版本的犰狳 9.870,现在有更好的方法来做到这一点。速度提升很小,尤其是在小矩阵上,但似乎是一致的。更重要的是,代码要短得多。

我调用新函数trimat2vec_new

vec trimat2vec_new(mat const& inmat){
  return(inmat.elem(trimatl_ind(size(inmat),-1)));
}

R中的简单基准:

a=matrix(1:900,30,30)

all(trimat2vec_new(a) == trimat2vec(a))

library(microbenchmark)
microbenchmark(trimat2vec_new(a),
               trimat2vec(a),
               times = 1000)

产量:

Unit: microseconds
              expr   min     lq     mean median    uq    max neval cld
 trimat2vec_new(a) 3.026 3.4060 3.633960  3.557 3.727 20.549  1000  a 
     trimat2vec(a) 3.116 3.6515 3.955116  3.787 3.958 42.981  1000   b

我特别喜欢新trimatl_ind功能的便利性。和小的速度改进。


推荐阅读