nalgebra: Implementing a function for a generic MatrixMN

921 Views Asked by At

I'm trying to implement the exp function for a generic square MatrixMN

pub fn exp<N, R>(m: &MatrixMN<N, R, R>, k: usize) -> MatrixMN<N, R, R>
where
    N: Scalar + One + Zero,
    R: DimName + DimNameAdd<R>,
    <R as DimName>::Value: Mul<<R as DimName>::Value>,
    <<R as DimName>::Value as Mul<<R as DimName>::Value>>::Output: generic_array::ArrayLength<N>,
{
    let mut i = MatrixMN::<N, R, R>::identity();
    i.add(&m)
}

But I keep getting this errors like this.

error[E0599]: no method named `add` found for struct `nalgebra::base::matrix::Matrix<N, R, R, nalgebra::base::array_storage::ArrayStorage<N, R, R>>` in the current scope
  --> src/state_extrapolation.rs:24:7
   |
24 |     i.add(&m)
   |       ^^^ method not found in `nalgebra::base::matrix::Matrix<N, R, R, nalgebra::base::array_storage::ArrayStorage<N, R, R>>`
   |
   = note: the method `add` exists but the following trait bounds were not satisfied:
           `&mut nalgebra::base::matrix::Matrix<N, R, R, nalgebra::base::array_storage::ArrayStorage<N, R, R>> : nalgebra::base::dimension::DimNameAdd<_>`
           `&nalgebra::base::matrix::Matrix<N, R, R, nalgebra::base::array_storage::ArrayStorage<N, R, R>> : nalgebra::base::dimension::DimNameAdd<_>`
           `nalgebra::base::matrix::Matrix<N, R, R, nalgebra::base::array_storage::ArrayStorage<N, R, R>> : nalgebra::base::dimension::DimNameAdd<_>`

Is there a better way to pass generic matrices to functions?

I've also tried with something like this

pub fn exp2<M>(m: &M, k: usize) -> M
where
    M: nalgebra::base::Matrix<_, _, _, _>,
{
    let mut i = M::identity();

    i.add(&m)
}

But cannot come up with good traits for M.

1

There are 1 best solutions below

4
On BEST ANSWER

It's easy to get lost in the traits when making things fully generic. My tips are:

  • Copy the signature of the impl block that implements similar functions to yours, e.g. the line DefaultAllocator: Allocator<N, R, R> from here allows getting rid of many constraints
  • Instead of Scalar, if it's going to be floats you will calculate with, it's easier to use RealField which gives you Scalar plus many other useful properties (like One and Zero required for the identity() function)
  • Follow the compiler errors – it suggested I add a use std::ops::Add, which made it work in the end.

Here is the code, playground:

use nalgebra::{
    base::allocator::Allocator, DefaultAllocator, DimName, DimNameAdd, MatrixN, RealField,
};
use std::ops::Add;

fn exp<N, R>(m: &MatrixN<N, R>, k: usize) -> MatrixN<N, R>
where
    N: RealField,
    R: DimName + DimNameAdd<R>,
    DefaultAllocator: Allocator<N, R, R>,
{
    let i = MatrixN::<N, R>::identity();
    m.add(i)
}