Armadillo cpp:访问 3D 字段的切片
Armadillo cpp: access slice of a 3D field
我在用 C++ 编写犰狳时遇到了以下问题:
给定一个 3D 字段 class,我无法访问它的各个切片。
这里有一小段代码来说明:
//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;
当我编译并执行这段代码时,我看到了:
字段正确显示。
它的第一片。
- 又是第一片。
我是不是做错了什么?
有人可以帮忙吗?
提前致谢!
塞尔吉奥
有趣,它看起来像是犰狳中的一个错误...
当您调用 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
中,而 "slice-offset" 存储在 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]);
}
这完全忽略了存储在 aux_slice1
中的 "slice-offset"。在 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
类似的 "effect" 也会影响 include/armadillo_bits/subview_field_meat.hpp
中的其他方法...
我在用 C++ 编写犰狳时遇到了以下问题: 给定一个 3D 字段 class,我无法访问它的各个切片。 这里有一小段代码来说明:
//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;
当我编译并执行这段代码时,我看到了:
字段正确显示。
它的第一片。
- 又是第一片。
我是不是做错了什么? 有人可以帮忙吗? 提前致谢!
塞尔吉奥
有趣,它看起来像是犰狳中的一个错误...
当您调用 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
中,而 "slice-offset" 存储在 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]);
}
这完全忽略了存储在 aux_slice1
中的 "slice-offset"。在 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
类似的 "effect" 也会影响 include/armadillo_bits/subview_field_meat.hpp
中的其他方法...