【问题标题】:How do I create an nalgebra static matrix by copying from a dynamic matrix view?如何通过从动态矩阵视图复制来创建代数静态矩阵?
【发布时间】:2021-07-12 18:57:02
【问题描述】:

我正在尝试通过从na::Matrix3 的前两行复制来创建na::Matrix2x3。结果将存储在结构中。

我不知道该怎么做,文档也很混乱。我尝试了clone()into()from(...) 等,但似乎没有任何效果。

这是我尝试使用.clone() (playground) 的可重现示例:

extern crate nalgebra as na; // 0.27.1

fn main() {
    let proj33 = na::Matrix3::<f64>::zeros();
    let proj: na::Matrix2x3<f64> = proj33.rows(0, 2).clone();
}
error[E0308]: mismatched types
 --> src/main.rs:5:36
  |
5 |     let proj: na::Matrix2x3<f64> = proj33.rows(0, 2).clone();
  |               ------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Const`, found struct `Dynamic`
  |               |
  |               expected due to this
  |
  = note: expected struct `Matrix<_, Const<2_usize>, _, ArrayStorage<f64, 2_usize, 3_usize>>`
             found struct `Matrix<_, Dynamic, _, SliceStorage<'_, f64, Dynamic, Const<3_usize>, Const<1_usize>, Const<3_usize>>>`

这似乎可行,但它首先将矩阵初始化为零是浪费:

let mut proj = na::Matrix2x3::<f64>::zeros();
proj.copy_from(&proj33.rows(0, 2));

在 Eigen (C++) 中我会这样做:

const Eigen::Matrix<double, 2, 3> proj = proj33.topRows(2);

【问题讨论】:

  • 很浪费——你确定它很浪费而且没有优化吗?
  • 即使它已经被优化了,如果事实证明nalgebra确实有一些构造方法可以在一行中完成,那么拥有一个不必要的mut是冗长和危险的.
  • dangerous 似乎有点反应过度了。另见What does 'let x = x' do in Rust?
  • 我的意思是危险的,因为额外的复杂性使得程序员在处理那段代码时更容易出错。想象一下,如果 Rust 不允许您分配整数,而您必须使用 let mut a = 0; a.copy(123); let a = a; 而不是 let a = 123;。然后,当询问是否有更好的方法来做到这一点时,人们会说,“啊,但它是安全的,并且可能已经被编译器优化了”。当然可以,但是后一种方法更难理解,并且如果您必须每次都这样做,则导致错误的可能性更大。

标签: rust nalgebra


【解决方案1】:

…或者可能更适合: fixed_rows()

let proj33 = na::Matrix2x3::<f64>::zeros();
let proj: na::Matrix2x3<f64> = proj33.fixed_rows::<2>(0).into();

【讨论】:

    【解决方案2】:

    现在,我有点同意@Shepmaster 的观点,这可能真的完全没有必要,但如果你绝对不能忍受用零初始化矩阵,你可以使用一点unsafe

    extern crate nalgebra as na;
    
    fn main() {
        let proj33 = na::Matrix3::<f64>::zeros();
        let proj = unsafe {
            // create a new matrix with probably a bunch of garbage in it
            let mut p = na::Matrix2x3::<f64>::new_uninitialized();
            // copy the data from the other matrix into the unitialized one
            (*p.as_mut_ptr()).copy_from(&proj33.rows(0, 2));
            // pinky promise that it's initialized now
            p.assume_init()
        };
        
        println!("{}", proj);
    }
    

    免责声明Matrix::new_unitialized 没有很好的文档记录,所以我不知道这是否真的安全,或者是否有一些我不知道的不变量。我不明白为什么这不应该是好的,但这些当然是著名的遗言。

    【讨论】:

    • 我很惊讶nalgebra 没有Matrix::new_from_copy 或某种简单地从矩阵复制东西的初始化程序。我想我会坚持使用::zero 然后......我同意你的观点,new_uninitialized 方法太hacky并且可能不安全。
    【解决方案3】:

    好的,我想通了。我必须使用fixed_slice 而不是(或除了)rows --- 因为编译器知道输出的大小(Matrix2x3),所以切片也必须是。

    关键是要使用:

    .fixed_slice::<2, 3>(0, 0).into()
    

    这适用于动态矩阵(playground)

    extern crate nalgebra as na;
    
    fn main() {
        let proj33 = na::DMatrix::identity(3, 3);
        let proj: na::Matrix2x3<f64> = proj33.fixed_slice::<2, 3>(0, 0).into();
    }
    

    还有动态矩阵视图(也就是使用 SliceStorage 而不是 ArrayStorage 的矩阵)(playground):

    extern crate nalgebra as na;
    
    fn main() {
        let proj33 = na::DMatrix::identity(3, 3);
        let proj33_view = proj33.rows(0, 2);
        dbg!(&proj33_view);
        let proj: na::Matrix2x3<f64> = proj33_view.fixed_slice::<2, 3>(0, 0).into();
    }
    

    但是,在对动态矩阵进行切片时,请记住,如果切片超出范围,它会出现恐慌。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      相关资源
      最近更新 更多