Search code examples
rustnalgebra

Performing basic operations with nalgebras most generic Matrix type


I'm trying to figure out how to write functions that take generic nalgebra matrices and vectors as their arguments and perform basic operations on those. I'm especially interested in being generic over fixed-size and dynamically sized matrices.

As an example, the following function is supposed to accept both SVector and DVector arguments and subtract them:

use nalgebra::{DVector, Matrix, U1, Dim, RawStorage, Storage};

fn function<R, S>(a: &Matrix<f64, R, U1, S>, b: &Matrix<f64, R, U1, S>)
    where R: Dim, S: RawStorage<f64, R> + Storage<f64, R>
{
    let c = b - a;
}

fn main() {
    let a = DVector::<f64>::zeros(3);
    let b = DVector::<f64>::zeros(3);
    function(&a, &b);
    
    let a = SVector::<f64, 3>::zeros();
    let b = SVector::<f64, 3>::zeros();
    function(&a, &b);
}

The subtraction however doesn't work and results in the following error:

error[E0369]: cannot subtract `&Matrix<f64, R, Const<1>, S>` from `&Matrix<f64, R, Const<1>, S>`
 --> src/main.rs:6:15
  |
6 |     let c = b - a;
  |             - ^ - &Matrix<f64, R, Const<1>, S>
  |             |
  |             &Matrix<f64, R, Const<1>, S>
  |
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
  |
4 |     where R: Dim, S: RawStorage<f64, R> + Storage<f64, R>, DefaultAllocator: nalgebra::allocator::Allocator<f64, R>
  |                                                          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0369`.

I'm not sure this can be solved by adding more trait bounds, as the compiler suggests, or if the Matrix type just doesn't support those operations at all.


Solution

  • The bound suggested by the compiler will work (that's why it suggested it in the first place), but in such cases I'd go with the literal requirement your code has rather than some obscure bound on the implementation of the desired trait (Sub here):

    use nalgebra::{DVector, Matrix, U1, Dim, RawStorage, Storage, SVector};
    
    fn function<'a, R, S>(a: &'a Matrix<f64, R, U1, S>, b: &'a Matrix<f64, R, U1, S>)
    where
        R: Dim,
        S: RawStorage<f64, R> + Storage<f64, R>,
        &'a Matrix<f64, R, U1, S>: std::ops::Sub<&'a Matrix<f64, R, U1, S>>,
    {
        let c = b - a;
    }
    
    fn main() {
        let a = DVector::::zeros(3);
        let b = DVector::::zeros(3);
        function(&a, &b);
        
        let a = SVector::::zeros();
        let b = SVector::::zeros();
        function(&a, &b);
    }
    

    And it works as expected.
    Playground