犰狳cpp:访问3D字段的切片

时间:2017-11-30 12:18:32

标签: c++ armadillo

我在c ++中使用armadillo,我遇到了以下问题: 给定一个3D字段类,我无法访问它的单个切片。 这里有一小段代码来说明它:

//Define field with chosen dimensions
field<mat> Test_field(2,2,2);

//Fill it with 2x2 random matrices in each position
for (int i=0;i<2;i++){
  for (int j=0;j<2;j++){
    for (int k=0;k<2;k++){
      Test_field(i,j,k)=randu(2,2);
       }}}

//Display results
cout<<Test_field<<endl;
cout<<Test_field.slice(0)<<endl;
cout<<Test_field.slice(1)<<endl;

当我编译并执行此代码时会发生什么:

  1. 正确显示该字段。

  2. 第一片。

  3. 它的第一片。
  4. 我做错了吗? 有人可以帮忙吗? 提前谢谢!

    塞尔吉奥

1 个答案:

答案 0 :(得分:1)

有趣的是,它看起来像犰狳中的一个错误......

当您调用slice函数时,Armadillo(版本8.300.0)会创建一个subview_field(最后一个参数表示您感兴趣的切片总数):

template<typename oT>
inline
subview_field<oT>
field<oT>::slice(const uword slice_num)
  {
  arma_extra_debug_sigprint();

  arma_debug_check( (slice_num >= n_slices), "field::slice(): out of bounds" );

  return subview_field<oT>(*this, 0, 0, slice_num, n_rows, n_cols, 1);
  }

现在,当创建subfield_view时,它会在n_slices中存储所请求的切片数量,并且&#34;切片偏移量&#34;在aux_slice1

template<typename oT>
arma_inline
subview_field<oT>::subview_field
  (
  const field<oT>& in_f,
  const uword      in_row1,
  const uword      in_col1,
  const uword      in_slice1,
  const uword      in_n_rows,
  const uword      in_n_cols,
  const uword      in_n_slices
  )
  : f(in_f)
  , aux_row1(in_row1)
  , aux_col1(in_col1)
  , aux_slice1(in_slice1)
  , n_rows(in_n_rows)
  , n_cols(in_n_cols)
  , n_slices(in_n_slices)
  , n_elem(in_n_rows*in_n_cols*in_n_slices)
  {
  arma_extra_debug_sigprint();
  }

例如,这个简化的程序会按预期打印1 1

#include <armadillo>
#include <iostream>

int main(){

    arma::field<double> F(1,1,3);

    for (int k=0;k<3;k++){
        F(0,0,k) = 100*k;
    }

    auto s = F.slice(1);
    std::cout << s.n_slices << '\t' << s.aux_slice1 << '\t' << std::endl;

    return 0;
}

现在让我们尝试修改这个切片:

#include <armadillo>
#include <iostream>

int main(){

    arma::field<double> F(1,1,3);

    for (int k=0;k<3;k++){
        F(0,0,k) = 100*k;
    }

    std::cout << F << std::endl;
    auto s = F.slice(1);
    s.fill(42);
    std::cout << F << std::endl;

    return 0;
}

但是,这会产生:

[field slice 0]
[field column 0]
0


[field slice 1]
[field column 0]
100


[field slice 2]
[field column 0]
200



[field slice 0]
[field column 0]
42


[field slice 1]
[field column 0]
100


[field slice 2]
[field column 0]
200

因此,Armadillo修改了原始字段的切片0,而不是选定的切片编号1。原因似乎是当子字段只有一个切片时,fill方法的行为有所不同:

template<typename oT>
inline
void
subview_field<oT>::fill(const oT& x)
  {
  arma_extra_debug_sigprint();

  subview_field<oT>& t = *this;

  if(t.n_slices == 1)
    {
    for(uword col=0; col < t.n_cols; ++col)
    for(uword row=0; row < t.n_rows; ++row)
      {
      t.at(row,col) = x;
      }
    }
  else
    {
    for(uword slice=0; slice < t.n_slices; ++slice)
    for(uword col=0;   col   < t.n_cols;   ++col  )
    for(uword row=0;   row   < t.n_rows;   ++row  )
      {
      t.at(row,col,slice) = x;
      }
    }
  }

因为它调用at方法的2参数版本:

template<typename oT>
arma_inline
oT&
subview_field<oT>::at(const uword in_row, const uword in_col)
  {
  const uword index = (in_col + aux_col1)*f.n_rows + aux_row1 + in_row;

  return *((const_cast< field<oT>& >(f)).mem[index]);
  }

完全忽略&#34;切片偏移&#34;存储在aux_slice1中。在at方法的3参数版本中正确考虑了此偏移量:

template<typename oT>
arma_inline
oT&
subview_field<oT>::at(const uword in_row, const uword in_col, const uword in_slice)
  {
  const uword index = (in_slice + aux_slice1)*(f.n_rows*f.n_cols) + (in_col + aux_col1)*f.n_rows + aux_row1 + in_row;

  return *((const_cast< field<oT>& >(f)).mem[index]);
  }

为了说明这一点,我们将上面的示例程序修改为:

auto s = F.slices(1, 2);
s.fill(42);

然后输出符合预期:

[field slice 0]
[field column 0]
0


[field slice 1]
[field column 0]
42


[field slice 2]
[field column 0]
42

类似&#34;效果&#34;影响include/armadillo_bits/subview_field_meat.hpp中的其他方法......