Using nalgebra in generics

help

#1

I have this code:

struct NPoint<N>(VectorN<usize, N>) where N : Dimension;

Where Dimension was defined as

trait Dimension: DimName + Dim {}

because of other errors in other generics.

The error I get at the struct definition is:

error[E0277]: the trait bound `<N as nalgebra::DimName>::Value: std::ops::Mul<typenum::UInt<typenum::UTerm, typenum::B1>>` is not satisfied
  --> src/lib.rs:24:18
   |
24 | struct NPoint<N>(VectorN<usize, N>) where N : Dimension;
   |                  ^^^^^^^^^^^^^^^^^^ no implementation for `<N as nalgebra::DimName>::Value * typenum::UInt<typenum::UTerm, typenum::B1>`
   |
   = help: the trait `std::ops::Mul<typenum::UInt<typenum::UTerm, typenum::B1>>` is not implemented for `<N as nalgebra::DimName>::Value`
   = help: consider adding a `where <N as nalgebra::DimName>::Value: std::ops::Mul<typenum::UInt<typenum::UTerm, typenum::B1>>` bound
   = note: required by `nalgebra::MatrixArray`

I have tried adding the help suggested by the compiler, but that just made it worse, I don’t even know what the error became, it just went on and on.

The docs said I could use typenum, so originally I tried to just use N : Unsigned in my generics, but I was getting errors about Dim and DimName, that’s why I defined Dimension. I tried looking at the definition of DimName but it’s too high level for me.

Full disclosure: I am pretty noobish at Rust.


#2

I ended up in what seems to be the same situation when trying to have a matrix of generic size inside a struct:

extern crate nalgebra as na;
use na::{Scalar, Dim, MatrixN};

fn main() {}

struct Container<T: Scalar, D: Dim>
{
    x: MatrixN<T, D>
}

That gives me this error:

error[E0277]: the trait bound `D: na::DimName` is not satisfied
 --> src/main.rs:8:5
  |
8 |     x: MatrixN<T, D>
  |     ^^^^^^^^^^^^^^^^ the trait `na::DimName` is not implemented for `D`
  |
  = help: consider adding a `where D: na::DimName` bound
  = note: required by `na::MatrixArray`

Just like you, chasing down the path of adding trait bounds didn’t seem to lead anywhere. What am I missing? Isn’t this how you’re supposed to do it?


#3

That kind of genericity is quite hard to use on the current version of nalgebra unfortunately. You might find that part of the documentation useful. All this will become much simpler when rust will support specialization of trait implementations…

In the mean time, the following should work for your examples:

extern crate nalgebra as na;
use na::{DefaultAllocator, Scalar, Dim, OwnedMatrix, OwnedColumnVector};
use na::dimension::U1;
use na::allocator::Allocator;

fn main() {}

struct NPoint<N: Dim>(OwnedColumnVector<usize, N, DefaultAllocator>)
    where DefaultAllocator: Allocator<usize, N, U1> ;

struct Container<T: Scalar, D: Dim>
    where DefaultAllocator: Allocator<T, D, D>
{
    x: OwnedMatrix<T, D, D, DefaultAllocator>
} 

In a near future release, this will be simplifiable to:

extern crate nalgebra as na;
use na::{DefaultAllocator, Scalar, Dim, VectorN, MatrixN};
use na::allocator::Allocator;

fn main() {}

struct NPoint<N: Dim>(VectorN<usize, N>)
    where DefaultAllocator: Allocator<usize, N> ;

struct Container<T: Scalar, D: Dim>
    where DefaultAllocator: Allocator<T, D, D>
{
    x: MatrixN<T, D>
}

Unfortunately, we can’t get rid of the where clauses without support of specialization.


#4

In version 0.14.0, the following works for dimensional genericity:

pub fn derive<N: Dim + DimName>(
        &mut self,
        t: f64,
        state: VectorN<f64, N>,
    ) -> (f64, VectorN<f64, N>)
    where
        DefaultAllocator: Allocator<f64, N>,
    {
     // ...
    }

P.S.: I slightly modified the code above to remove a Fn closure parameter, but I think this code is correct. With the Fn parameter, it compiles and the tests run.